实验结果
1、功能需求:
该聊天工具是在Linux平台下进行开发与实现的,可以实现多人通信和交流。系统采用了TCP/IP协议和socket接口。从总体来讲,该聊天系统主要包括服务端与客户端。
服务端功能实现模块:
用户通过用户名和密码进行登录
等待客户端进行身份验证,登录
接收和发送用户聊天信息功能(接受发信用户发来的信息,再将信息转发到收信用户)
客户端功能实现模块:
验证登录用户的信息
客户端之间进行信息传递交流
保存聊天记录
2、功能模块图:
(1) 服务器端:
服务器端登录时与用户名和密码相关联,成功登陆后,可以开启多个客户端,服务器端通过send()函数来向客户端发送服务器端开启的消息,通过accept()接收了客户端连接的请求,连接成功,实现了多人在线聊天的功能。发送消息时,将存储的消息以char *的形式通过函数给socket通信。接收消息时,当有消息传来,通过recv()函数先检查套接字sock的接收缓冲区,如果sock的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一起等待,直到把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据copy到rbuf中,可以显示在聊天界面的文本框内。
(2) 客户端:
多个客户端在和服务器端连接成功后,开始进行多人在线聊天,通过checklogin()函数实现用户名和密码匹配,从而实现用户登录,验证完之后开始进行多人聊天,通过save()函数将聊天记录保存Loginfo.txt
同样用户发送消息时通过send()函数向服务器端发送消息,通过recv()函数来接收消息内容。
(3) 系统总结构:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 54188
#define MAX_CLIENT 10
client.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
服务器端代码:
Server.c:
struct client{
int s;
char name[50];
int online;
};
static int sock;
static char rbuf[1024];
static char wbuf[1024];
static struct sockaddr_in server,client;
static struct client cli[MAX_CLIENT];
int main(int argc,char *argv[]){
int max_sock;
int len;
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock==-1){
perror("socket");
return 1;
}
max_sock=sock;
bzero(&server,sizeof(server));
server.sin_port=htons(PORT);
server.sin_addr.s_addr=INADDR_ANY;
server.sin_family=AF_INET;
if(bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr))==-1){
perror("bind");
return 2;
}
listen(sock,MAX_CLIENT);
int i=0,j=0;
fd_set rfd;
while(1){
FD_ZERO(&rfd);
FD_SET(sock,&rfd);
for(i=0;i<MAX_CLIENT;i++){
if(cli[i].s==0)
continue;
FD_SET(cli[i].s,&rfd);
}
switch(select(max_sock+1,&rfd,NULL,NULL,NULL)){
case 0:
continue;
case -1:
continue;
default:
if(FD_ISSET(sock,&rfd)){
for(i=0;i<MAX_CLIENT;i++){
if(cli[i].s==0){
len=sizeof(struct sockaddr);
cli[i].s=accept(sock,(struct sockaddr *)&client,&len);
if(cli[i].s==-1){
perror("accept");
cli[i].s=0;
break;
}
cli[i].online=0;
if(cli[i].s>max_sock)
max_sock=cli[i].s;
printf("accept!\n");
break;
}
}
}
for(i=0;i<MAX_CLIENT;i++){
if(cli[i].s==0)
continue;
if(FD_ISSET(cli[i].s,&rfd)){
int rsize;
bzero(rbuf,sizeof(rbuf));
rsize=recv(cli[i].s,rbuf,sizeof(rbuf),0);
if(rsize>0){
printf("%s\n",rbuf);
if(cli[i].online){
for(j=0;j<MAX_CLIENT;j++){
if(cli[j].s==0 || j==i || cli[j].online==0)
continue;
bzero(wbuf,sizeof(wbuf));
strcpy(wbuf,cli[i].name);
strcat(wbuf,rbuf);
send(cli[j].s,wbuf,strlen(wbuf)+rsize,0);
}
if(!strcmp(rbuf,"bye\n")){
send(cli[i].s,"quit",4,0);
close(cli[i].s);
cli[i].s=0;
cli[i].online=0;
memset(cli[i].name,0,sizeof(cli[i].name));
}
}
else{
if(!strncmp(rbuf,"#name",5)){
strcpy(cli[i].name,rbuf+5);
cli[i].online=1;
}
}
}
}
}
}
}
return 0;
}
Client.c:
int main(int argc,char *argv[]){
FILE *fp;
char logname[100];
char pwd[100];
int temp;
printf("please input username:");
scanf("%s",&logname);
printf("please input password:");
scanf("%s",&pwd);
if(checklogin(logname, pwd, temp) == 0)
return 0;
int i,j,err;
char name[100];
int rsize,wsize;
sock=socket(AF_INET,SOCK_STREAM,0);
if(sock==-1){
perror("socket");
return 1;
}
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr("127.0.0.1");
server.sin_port=htons(54188);
err=connect(sock,(struct sockaddr *)&server,sizeof(struct sockaddr));
if(err==-1){
perror("connect");
return 2;
}
printf("connect success!\n");
bzero(rbuf,sizeof(rbuf));
bzero(name,sizeof(name));
rsize=read(STDIN_FILENO,rbuf,sizeof(rbuf));
rbuf[strlen(rbuf)-1]='\0';
sprintf(name,"#name%s:",rbuf);
send(sock,name,sizeof(name),0);
j=0;i=0;
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(STDIN_FILENO,&rfd);
FD_SET(sock,&rfd);
while(1){
FD_ZERO(&rfd);
FD_SET(STDIN_FILENO,&rfd);
FD_SET(sock,&rfd);
switch(select(sock+1,&rfd,NULL,NULL,NULL)){
case -1:
case 0:
continue;
default:
if(FD_ISSET(STDIN_FILENO,&rfd)){
bzero(rbuf,sizeof(rbuf));
rsize=read(STDIN_FILENO,rbuf,sizeof(rbuf));
if(rsize>0){
send(sock,rbuf,rsize,0);
save(name,rbuf);
}
}
if(FD_ISSET(sock,&rfd)){
bzero(rbuf,sizeof(rbuf));
rsize=recv(sock,rbuf,sizeof(rbuf),0);
if(rsize>0){
printf("\033[34m%s\033[30m\n",rbuf);
if(!strcmp(rbuf,"quit")){
close(sock);
return 11;
}
}
}
}
}
return 0;
}
保存聊天记录:
Client.c:
void save(char name[],char s[])
{
time_t t;
char buf[1024];
FILE *fp;
int i;
int n;
fp=fopen("record.txt","a");
if(!fp)
{
printf("file open fail!");
exit(0);
}
time(&t);
ctime_r(&t,buf);
fprintf(fp,"%s",buf);
fprintf(fp,"%s",name);
fprintf(fp,"%s",s);
fclose(fp);
printf("data save successfull\n");
}
用户名和密码登录:
Client.c:
int checklogin(char *loginname,char *loginpassword,int flag){
FILE *fp;
char user_name[100],user_pwd[100];
if(!(fp = fopen("/home/test/src/keshe/Loginfo.txt","r"))){
perror("file open error!");
return 0;
}
while(fscanf(fp,"%s %s",user_name,user_pwd)!=EOF){
if(!strcmp(loginname, user_name) && !strcmp(loginpassword, user_pwd))
return 1;
}
fclose(fp);
return 0;
}
将系统开启时间记录到日志中:
Server.c:
char tm[1024];
FILE *fp;
time_t t;
fp=fopen("demo.log","a");
if(!fp)
{
printf("file open fail!");
exit(0);
}
time(&t);
ctime_r(&t,tm);
fprintf(fp, "%s the chat system start", tm);
Makefile文件:
target:server.o client.o
gcc -o server server.o
gcc -o client client.o
server.o:server.c
gcc -c -o server.o server.c
client.o:client.c
gcc -c -o client.o client.c
clean:
rm *.o server client
.PHONY:clean
储存聊天记录文件 Loginfo.txt
本次Linux期末采取了大作业的方式,老师布置了做一个简易的多人在线聊天系统。确实对于编程能力很弱的我,出现了很多问题,而且对于老师的要求有的完成的不够全面。
首先,开始对socket原理不是很熟悉,只是上课老师让我们练习过几次,但根据网上查阅的资料,也顺利的完成了多人在线聊天的功能。之后开始完成用户登录这一项功能,但是遇到了很多问题,无法进行注册功能,所以登录功能不是很完善,只能做到在.txt文件中输入用户信息和密码,然后在登录的时候去和文件中的信息进行匹配,完成了一个登录功能,后续功能还需要继续完善。接下来就是保存聊天记录功能,这个功能是将客户发送信息给写进文件中,开始只能将聊天内容保存,但是不能区分是哪个用户说的,后来通过写入用户姓名,和服务器端做了一个连接,解决了这一问题,后来还练习了获取系统时间函数,成功保存了时间、客户姓名和内容记录。但是唯一最后没有解决的是守护进程的编写,没有成功建立服务器端。所以此项功能没有实现,在此说明一下,后续会继续研究,将功能完善。
此次编写程序,不仅让我巩固了这学期所学的Linux的知识,而且更加熟练的掌握了socket(套接字)的用法,而且还掌握了一些以前不熟悉的操作,比如文件的写入,获取系统时间等等,所以通过这次实验收获还是很多的,对自己动手能力也是有了很大的提高,但是还有很多不足,以后慢慢改善。