//client.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <signal.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <sys/types.h> #include <fcntl.h> #include <sys/stat.h> #define MAXLEN 1024 /*消息类型*/ struct message { char flag[15]; char name[10]; int size; char msg[MAXLEN]; }; struct msq { long msg_type; char msg_text[5]; }; int qid=-1,fd=-1,sockfd,savefilefd=-1; char filefromname[10]; void handleQuit(int signal_no) { if(fd>0) close(fd); close(sockfd); if(qid>0) { if((msgctl(qid,IPC_RMID,NULL))<0) //删除消息队列 { printf("消息队列无法关闭\n"); exit(1); } } close(savefilefd); printf("程序正常退出\n"); raise(SIGQUIT); } /******************************************************************* *功能:切割字符串 *参数:c为分隔符,left为分割后存放左边字符串,right为分隔后存放右边字符串 ******************************************************************/ void cutStr(char str[],char left[], int n, char right[],int m, char c) { int i,k,j; for(i = 0 ; i < n ;i++) { if(str[i] == c) break; } if(i == n) { i = -1; } else { memset(left,0,strlen(left)); for(k = 0 ; k < i ; k++) { left[k] = str[k]; } } for(j = i+1 ; j < m;j++) { if(str[j] == '\0') break; right[j-i-1] = str[j]; } left[i] = '\0'; if(j < m) right[j-i-1] = '\0'; else right[m] = '\0'; } struct msq msg; time_t timep; void handlerecvmsg(int *sockfd) { int connfd = *sockfd; int nread; char buf[1024]; char str[1024]; struct message recvmsg; // time_t timep; //struct msq msg; if(( fd =open("chatlog.txt",O_RDWR|O_APPEND))< 0) { perror("打开聊天记录文件失败!"); exit(1); } if((qid = msgget(2222,IPC_CREAT|0666)) == -1) { printf("创建消息队列失败\n"); exit(1); } msg.msg_type = getpid(); strcpy(msg.msg_text,"OK"); while(1) { nread = recv(connfd,&recvmsg,sizeof(struct message),0); if(nread == 0) { printf("与服务器断开了连接\n"); close(fd); close(connfd); exit(0); } else if (strcmp(recvmsg.flag,"all") == 0) //客户发给所有人 { time (&timep); sprintf(str,"%s%s发给所有人:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg); } else if (strcmp(recvmsg.flag,"view") == 0) //查看所有在线用户 { time (&timep); printf("%s当前在线客户端:\n%s\n\n",ctime(&timep),recvmsg.msg); continue; } else //私聊 { time (&timep); sprintf(str,"%s%s发来的私聊消息:%s\n\n",ctime(&timep),recvmsg.name,recvmsg.msg); } write(fd,str,strlen(str)); //写文件,保存消息记录 //printf("%s",msg); msgsnd(qid,&msg,sizeof(struct msq),0); } } int main(int argc,char *argv[]) { struct sockaddr_in server_addr; int port; int do_number; struct message a; char str[MAXLEN]; char buf[MAXLEN]; pthread_t pid; if(argc != 3) { printf("请输入服务器IP和端口\n"); exit(1); } port = atoi(argv[2]); if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) { printf("创建socket失败\n"); exit(1); } signal(SIGINT,handleQuit); printf("----------------------------------\n"); printf("||\n"); printf("| input a number to work |\n"); printf("|\t1.login\t\t\t |\n"); printf("|\t2.register\t\t |\n"); printf("|\t3.exit\t\t\t |\n"); printf("||\n"); printf("----------------------------------\n"); scanf("%d",&do_number); gets(str); while(do_number != 1 && do_number != 2 && do_number != 3) { printf("你输入的不是上面的选项,请重新输入:\n"); scanf("%d",&do_number); gets(str); } if(do_number==3) { close(sockfd); printf("程序已退出!\n"); exit(0); } bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(argv[1]); server_addr.sin_port = htons(port); if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1) { printf("与服务器无响应,请隔一段时间再连接\n"); exit(2); } if(do_number ==1) //登陆 { int n = 3; while(n) { printf("请输入你的用户名:\n"); scanf("%s",a.name); printf("请输入密码:\n"); scanf("%s",a.msg); strcpy(a.flag,"login"); //a.flag[3] = '\0'; send(sockfd,&a,sizeof(a),0); printf("正在等待服务器应答...\n"); recv(sockfd,buf,MAXLEN,0); printf("接到服务器发来的信息:%s\n",buf); if(strcmp(buf,"登录成功!") == 0) { //int i,j,k; pthread_create(&pid,NULL,(void*)handlerecvmsg,(void *)&sockfd); //创建线程来处理接收的消息 gets(str); strcpy(a.flag,"all"); while(1) { memset(a.msg,0,strlen(a.msg)); memset(str,0,strlen(str)); gets(str); strcpy(buf,a.flag); cutStr(str,a.flag,15,a.msg,MAXLEN,'$'); printf("标志信息为:%s\n",a.flag); if(strcmp(a.flag,"view") == 0) { send(sockfd,&a,sizeof(a),0); strcpy(a.flag,buf); continue; } else { send(sockfd,&a,sizeof(a),0); time (&timep); sprintf(str,"%s我发给%s的私聊消息:%s\n\n",ctime(&timep),a.flag,a.msg); write(fd,str,strlen(str)); msgsnd(qid,&msg,sizeof(struct msq),0); continue; } } } else { n--; printf("您还有%d次机会,之后将退出程序!\n",n); } } close(sockfd); exit(3); } else if(do_number ==2) //注册 { int i =1 ; char username[10]; char password[20]; char password_t[20]; char temp[20]; printf("请输入你的用户名:\n"); scanf("%s",username); while(i) { printf("请输入密码:\n"); scanf("%s",password); printf("youpass : %s\n",password); printf("请再次输入密码:\n"); scanf("%s",password_t); printf("passyou : %s\n",password_t); if(strcmp(password,password_t) != 0) { printf("输入的密码不一样\n"); i = 1; } else { i = 0; } } strcpy(a.name,username); strcpy(a.msg,password); strcpy(a.flag,"reg"); //a.flag[3] = '\0'; send(sockfd,&a,sizeof(a),0); printf("正在等待服务器应答...\n"); recv(sockfd,buf,MAXLEN,0); printf("接到服务器发来的信息:%s\n",buf); } close(sockfd); return 0; }
//display.c #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <sys/msg.h> #include <sys/ipc.h> #include <sys/types.h> int qid,fd; struct msq { long msg_type; char msg_text[5]; }; void handlequit(int sign_no) { close(fd); if((msgctl(qid,IPC_RMID,NULL)) < 0) { printf("消息队列无法关闭\n"); exit(1); } printf("程序正常退出\n"); raise(SIGQUIT); } int main() { char buf[1024]; int n; struct msq msg; fd = open("chatlog.txt",O_RDONLY|O_CREAT); signal(SIGINT,handlequit); if(fd<0) { printf("打开文件失败\n"); return -1; } lseek(fd,0,SEEK_END); if((qid = msgget(2222,IPC_CREAT|0666)) == -1) { printf("创建消息队列失败\n"); close(fd); return -1; } while(1) { if(msgrcv(qid,&msg,sizeof(msg),0,0) < 0) { printf("读取消息对列失败\n客户端可能已经退出本程序将一起退出\n"); close(fd); return -1; } memset(buf,0,sizeof(buf)); n = read(fd,buf,1024); write(STDOUT_FILENO,buf,n); } close(fd); return 0; }
//check.c #include "check.h" int reg_check(struct message *recievemsg) { int fd; int read_size,write_size; struct message cmpmsg; if(strlen(recievemsg->name)>10 || strlen(recievemsg->msg)>20 ) { return 1; } if(strcmp(recievemsg->name,"all")==0) { return -1; } if(strcmp(recievemsg->name,"reg")==0) { return -1; } if(strcmp(recievemsg->name,"login")==0) { return -1; } if(strcmp(recievemsg->name,"trans")==0) { return -1; } if((fd=open("user.txt",O_RDWR|O_APPEND|0666))<0) { perror("open"); printf("open\n"); return -2; } do { if((read_size=read(fd,&cmpmsg,sizeof(cmpmsg)))< 0) { perror("read"); close(fd); return -2; } if(read_size != sizeof(struct message) && read_size !=0) { close(fd); return -2; } if(strcmp(recievemsg->name,cmpmsg.name)==0) { close(fd); return -1; } }while(read_size == sizeof(struct message)); if((write_size=write(fd,recievemsg,sizeof(struct message)))<0) { perror("write"); close(fd); return -2; } while(write_size!=sizeof(struct message)) { //write_size = 0-writesize; lseek(fd,-write_size,SEEK_CUR); write_size=write(fd,recievemsg,sizeof(struct message)); } printf("write file success\n"); close(fd); return 0; } int login_check(struct message *recievemsg) { int fd; struct message cmpmsg; int read_size; if((fd=open("user.txt",O_RDONLY))<0) { perror("open"); return -2; } do { if((read_size=read(fd,&cmpmsg,sizeof(struct message)))<0) { perror("read"); close(fd); return -2; } if(read_size != sizeof(struct message) && read_size!=0) { close(fd); return -2; } if((strcmp(recievemsg->name,cmpmsg.name)==0 )&&(strcmp(recievemsg->msg,cmpmsg.msg)==0)) { close(fd); return 0; } }while(read_size>0); close(fd); return -1; }
//check.h #include <fcntl.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <pthread.h> #define MAXLEN 1024 struct message { char flag[15]; char name[10]; int size; char msg[MAXLEN]; }; int reg_check(struct message *recievemsg); int login_check(struct message *recievemsg);
//linklist.c #include "linklist.h" LinkList CreateLinkList() { LinkList L = (LinkList)malloc(sizeof(LNode)); L->next = NULL; return L; } void deletelist(LinkList L ,datatype e) { int i=0; LinkList s,p; p = L; while ( (strcmp(p->data.name,e.name) != 0) && p->next != NULL) { s=p; p = p->next; } if (p->next == NULL && (strcmp(p->data.name,e.name) != 0)) { return; } else { s->next = p->next; free(p); } } void insertend(LinkList L,datatype e) { int i=0; LinkList s,p; p = L; while(p->next != NULL) { p = p->next; i++; } s = (LinkList)malloc(sizeof(LNode)); s->data =e; s->next = p->next ; p->next =s; } void DisplayList(LinkList L) { L=L->next; int i = 1; while (L != NULL) { printf("%d. %s \n",i,L->data.name); L = L->next; i++; } }
//linklist.h #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <errno.h> #include <netinet/in.h> #include <pthread.h> /*客户端信息*/ typedef struct _clientinf { char name[10]; struct sockaddr_in addr_in; int decr; pthread_t pid; }clientinf; typedef clientinf datatype; /*链表节点*/ typedef struct _LNode { datatype data; struct _LNode * next; }LNode,*LinkList; extern LinkList CreateLinkList(void); extern void deletelist(LinkList L ,datatype e); extern void insertend(LinkList L,datatype e); extern void DisplayList(LinkList L);
#server: server:server.o linklist.o check.o gcc server.o linklist.o check.o -lpthread -o server server.o:server.c check.h linklist.h gcc -c server.c check.o:check.c check.h gcc check.c -c clean: rm server.o linklist.o check.o server
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <errno.h> #include <netinet/in.h> #include <pthread.h> #include <arpa/inet.h> #include <signal.h> #include "linklist.h" #include "check.h" LinkList clientlink; //客户端信息链表 /**************************************************** *功能:处理信息 *****************************************************/ void handlesignal() { int choose; char name[10]; while(1) { printf("1.T除指定客户端,2.关闭服务器,3.显示在线客户端\n"); scanf("%d",&choose); while(choose < 1 || choose > 3) { printf("请输入上面提示的选项:\n"); scanf("%d",&choose); } gets(name); if(choose == 1) { printf("请输入你踢出去的客户端名字:\n"); gets(name); if(strcmp(name,"") == 0) continue; LinkList L,s; L = clientlink; L=L->next; s = L; while((strcmp(L->data.name,name) != 0) && L->next != NULL) { s = L; L = L->next; } //printf("1%s\n",L->data.name); if(L->next == NULL && (strcmp(L->data.name,name) != 0)) { printf("该客户端不存在\n"); } else { close(L->data.decr); //关闭套接字 pthread_cancel(L->data.pid); //关闭对应线程 s->next = L->next; free(L); } printf("3\n"); } else if(choose == 2) return; else if(choose == 3) { DisplayList(clientlink); } } } /*********************************************************** *函数功能:处理客户请求 **********************************************************/ void handleclient (clientinf *client) { clientinf clientNode = *client; int nread; struct message a; LinkList transfileNode; char buf[MAXLEN],str[MAXLEN]; while(1) { nread =recv(clientNode.decr,&a,sizeof(a),0); if(nread == 0) { strcpy(a.flag,"sermsg"); printf("客户端%s退出\n",clientNode.name); deletelist(clientlink ,clientNode); LinkList L; L = clientlink; L=L->next; sprintf(buf,"客户端%s退出\n",clientNode.name); while(L != NULL) { send(L->data.decr,buf,strlen(buf)+1,0); L = L->next; } return; } if(strcmp(a.flag,"login") == 0) //登录 { int i; i = login_check(&a); if(i == 0) { strcpy(buf,"登录成功!"); strcpy(clientNode.name,a.name); insertend(clientlink,clientNode); send(clientNode.decr,buf,strlen(buf)+1,0); } else { strcpy(buf,"登录失败!"); send(clientNode.decr,buf,strlen(buf)+1,0); } continue; } else if(strcmp(a.flag,"reg") == 0) //注册 { int i; i = reg_check(&a); if(i == 0) { strcpy(buf,"注册成功!"); strcpy(clientNode.name,a.name); send(clientNode.decr,buf,strlen(buf)+1,0); } continue; } else if (strcmp(a.flag,"all") == 0) //给所有人发消息 { if (strcmp(a.msg,"") != 0) { LinkList L; L = clientlink; L=L->next; strcpy(a.name,clientNode.name); while(L != NULL) { send(L->data.decr,&a,sizeof(struct message),0); L = L->next; } } continue; } else if(strcmp(a.flag,"view") == 0) //查看用户列表 { LinkList L; int i = 1; L = clientlink; L=L->next; memset(buf,0,strlen(buf)); while(L != NULL) { memset(str,0,strlen(str)); sprintf(str,"%d. %s\n",i,L->data.name); strcat(buf,str); //将消息合成一个消息 L = L->next; i++; } strcpy(a.name,clientNode.name); strcpy(a.msg,buf); send(clientNode.decr,&a,sizeof(struct message),0); continue; } else //私聊 { LinkList L; L = clientlink; L=L->next; strcpy(a.name,clientNode.name); while(L != NULL) { if (strcmp(L->data.name,a.flag) == 0) { send(L->data.decr,&a,sizeof(struct message),0); break; } L = L->next; } continue; } } } /*********************************************************** *函数功能:处理接受请求 ************************************************************/ void handleaccept(int *serverfd) { socklen_t client_len; int sockfd = *serverfd; clientinf clientNode; struct sockaddr_in client_addr; while(1) { client_len =sizeof(struct sockaddr_in); if((clientNode.decr = accept(sockfd,(struct sockaddr *)&client_addr,&client_len)) == -1) { printf("接收连接失败\n"); } else { printf("与%s:%d连接建立成功\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); clientNode.addr_in = client_addr; pthread_create(&clientNode.pid,NULL,(void *)handleclient,(void *)&clientNode); //只要有连接请求,就创建线程来处理 } } } int main(int argc ,char *argv[]) { struct sockaddr_in server_addr,client_addr; int sockfd,connectfd,port,nread; pthread_t pid; char buf[MAXLEN]; char str[MAXLEN]; if(argc != 2) { printf("请输入端口\n"); exit(1); } if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) { printf("创建socket失败\n"); exit(1); } clientlink = CreateLinkList(); clientlink->data.decr = sockfd; port = atoi(argv[1]); bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr =htonl(INADDR_ANY); server_addr.sin_port = htons(port); if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1) { printf("绑定端口失败,端口可能被占用\n"); exit(2); } if(listen(sockfd,20) == -1) { printf("监听端口失败\n"); exit(3); } printf("正在监听中...\n"); pthread_create(&pid,NULL,(void*)handleaccept,(void *)&sockfd); handlesignal(); return 0; }