/*----------------------------server-------------------------*/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <fcntl.h> #include<netdb.h> #define PORT 8888 #define MAXLINE 1024 #define MAXSTEN 20 int n=0,client[MAXSTEN]; fd_set allset; /*---------------------------------------------------------------------------------------*/ /* */ /* 链表各个功能函数 */ /* */ /*---------------------------------------------------------------------------------------*/ struct client_msg { char name[20]; char *clientip; int fdnumber; int portnumber; struct client_msg *next; }; struct client_msg *list_create() { struct client_msg *lhead; lhead=(struct client_msg *)malloc(sizeof(struct client_msg)); lhead->next=NULL; return lhead; } void list_save(struct client_msg *head,char name[20],int ifdnumber,int iportnumber) { struct client_msg *ihead,*inew; ihead=head; inew=(struct client_msg *)malloc(sizeof(struct client_msg)); strcpy(inew->name,name); inew->fdnumber=ifdnumber; inew->portnumber=iportnumber; inew->next=NULL; if(NULL==head) { ihead=inew; }else{ while(ihead->next!=NULL)ihead=ihead->next; ihead->next=inew; } } void list_delect(struct client_msg *head,int dfd) { struct client_msg *dhead; dhead=head; if(NULL==head) { printf("链表为空!\n"); return; }else if(NULL==head->next){ if(head->fdnumber!=dfd) { printf("没有找到相关套接字!\n"); return; }else{ dhead=dhead->next; } }else{ while(dhead->next->fdnumber!=dfd)dhead=dhead->next; dhead->next=dhead->next->next; } } char *list_find(struct client_msg *head,int ffd) { struct client_msg *fhead; fhead=head; if(NULL==head) { printf("链表为空!\n"); }else{ while(fhead->fdnumber!=ffd)fhead=fhead->next; return fhead->name; } } void list_print(struct client_msg *head) { struct client_msg *phead; phead=head; if(NULL==head) { printf("链表为空!\n"); }else{ printf("\n\n目前服务器在线人数:%d",\n); printf("n-----------------------------------------------------------------n"); printf("\t\t昵称:\t\t端口:\t\t套接字:\n"); while(phead!=NULL) { printf("\t\t%s\t\t%d\t\t%d\n", phead->name,phead->portnumber,phead->fdnumber); phead=phead->next; } printf("\n-----------------------------------------------------------------\n"); } } /*---------------------------------------------------------------------------------------*/ /* */ /* 服务器各个功能函数 */ /* */ /*---------------------------------------------------------------------------------------*/ int server_create() { int listenfd; struct sockaddr_in servaddr; if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1) { printf("socket error:%s\n",strerror(errno)); exit(1); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(PORT); servaddr.sin_addr.s_addr=INADDR_ANY; if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1) { printf("bind error:%s\n",strerror(errno)); exit(1); } if(listen(listenfd,MAXSTEN)==-1) { printf("listen error:%s\n",strerror(errno)); exit(1); } printf("等待客户端连接... ...\n"); return listenfd; } int server_accept(int listenfd,struct client_msg *head) { int connfd; struct sockaddr_in cliaddr; socklen_t clilen; char tempname[20]; printf("发现新的客户端正在连接服务器... ...\n"); clilen=sizeof(cliaddr); if((connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen))==-1) { printf("accept error :%s\n",strerror(errno)); exit(1); } recv(connfd,tempname,sizeof(tempname),0); printf("客户端连接服务器成功!正在获取客户端的资料... ...\n"); printf("昵称:%s,端口:%d,IP地址:%s\n", tempname,ntohs(cliaddr.sin_port),inet_ntoa(cliaddr.sin_addr)); list_save(head,tempname,connfd,ntohs(cliaddr.sin_port)); n++; list_print(head); return connfd; } void server_recv(struct client_msg *head,int sockfd,int i) { char name[20],buff[MAXLINE+1]; int len,k; memset(buff,0,sizeof(buff)); len=recv(sockfd,buff,sizeof(buff),0); if(len==0) { strcpy(name,list_find(head,sockfd)); printf("\n用户%s 主动退出了聊天室!\n",name); close(sockfd); FD_CLR(sockfd,&allset); list_delect(head,sockfd); client[i]=-1; n--; list_print(head); }else if(len<0){ strcpy(name,list_find(head,sockfd)); printf("\n由于网络异常!用户%s 掉线!\n",name); printf("error:%s\n",strerror(errno)); close(sockfd); FD_CLR(sockfd,&allset); list_delect(head,sockfd); client[i]=-1; n--; list_print(head); }else{ printf("%s",buff); for(k=0;k<MAXSTEN;k++) { if(client[k]>0) { send(client[k],buff,sizeof(buff),0); } } memset(buff,0,sizeof(buff)); } } void server_command(struct client_msg *head) { int chance,fd,j; char commandbuff[20]; fgets(commandbuff,sizeof(commandbuff),stdin); if(strcmp(commandbuff,"command\n")==0) { printf("\n\n\n1.查看服务器成员\n2.断开成员的连接\n3.退出服务器\n"); printf("请输入:"); scanf("%d",&chance); switch (chance) { case 1: list_print(head); break; case 2: printf("请输入客户端的套接字:"); scanf("%d",&fd); memset(commandbuff,0,sizeof(commandbuff)); strcpy(commandbuff,list_find(head,fd)); list_delect(head,fd); close(fd); FD_CLR(fd,&allset); for(j=0;j<MAXSTEN;j++) { if(client[j]==fd) { client[j]=-1; break; } } n--; printf("\n用户%s 已经被强制下线!\n",commandbuff); list_print(head); break; case 3: printf("服务器已经关闭!\n"); exit(0); break; default: printf("不是有效命令!!\n"); break; } } } int main() { int listenfd,sockfd; int i,maxfd; struct client_msg *head; listenfd=server_create(); maxfd=listenfd; for(i=0;i<MAXSTEN;i++) { client[i]=-1; } head=list_create(); while(1) { FD_ZERO(&allset); FD_SET(0,&allset); FD_SET(listenfd,&allset); for(i=0;i<MAXSTEN;i++) { if(client[i]>0) FD_SET(client[i],&allset); } select(maxfd+1,&allset,NULL,NULL,NULL); if(FD_ISSET(listenfd,&allset)) { for(i=0;i<MAXSTEN;i++) { if(client[i]<0) { client[i]=server_accept(listenfd,head); FD_SET(client[i],&allset); break; } } if(i==MAXSTEN) { printf("已经达到服务器人数上限!无法建立新的连接\n"); } if(client[i]>maxfd) maxfd=client[i]; } if(FD_ISSET(0,&allset)) { server_command(head); } for(i=0;i<MAXSTEN;i++) { if((sockfd=client[i])<0) { continue; }else{ if(FD_ISSET(sockfd,&allset)) { server_recv(head,sockfd,i); break; } } } } return 0; } /*-----------------------------------client---------------------------------------*/ #include<lilin.h> //跟server 的头文件一样 #include<time.h> #define PORT 8888 #define MAXLINE 1024 int main(int argc, char *argv[]) { int sockfd,maxfd,len; char msg1[MAXLINE+1]; char msg2[MAXLINE+1]; char msg3[MAXLINE+1]; char name[40],*str; char strquit[]={"quitn"}; int quit=1; static char timestr[40]; struct sockaddr_in servaddr; time_t t; struct tm *nowtime; fd_set allset; if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { printf("socket error :%d %sn",errno,strerror(errno)); exit(1); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(PORT); servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); printf("正在连接服务器... ...\n"); if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1) { printf("connect error :%s\n",strerror(errno)); exit(1); } printf("连接服务器成功!\n"); printf("请输入你的昵称:"); scanf("%s",name); send(sockfd,name,sizeof(name),0); printf("%s 欢迎来到聊天室!(quit->退出)\n",name); fflush(stdin); maxfd=sockfd; while(1) { FD_ZERO(&allset); FD_SET(sockfd,&allset); FD_SET(0,&allset); memset(msg1,0,sizeof(msg1)); memset(msg2,0,sizeof(msg1)); memset(msg3,0,sizeof(msg1)); select(maxfd+1,&allset,NULL,NULL,NULL); if(FD_ISSET(0,&allset)) { fgets(msg1,sizeof(msg1),stdin); if(strcmp(msg1,strquit)==0) { close(sockfd); printf("已经断开与服务器的连接,退出聊天室!\n"); quit=0; } else { time(&t); nowtime=localtime(&t); strftime(timestr,sizeof(timestr),"%Y-%m-%d %H:%M:%S",nowtime); snprintf(msg2,sizeof(msg2),"%s %s:%s",timestr,name,msg1); send(sockfd,msg2,sizeof(msg2),0); } } if(FD_ISSET(sockfd,&allset)) { if(quit) { len=recv(sockfd,msg3,sizeof(msg3),0); if(len<=0) { printf("服务器出现故障,已经断开与服务器的连接!\n"); quit=0; close(sockfd); } else { printf("%s",msg3); } } else { printf("已经断开与服务器的连接,无法发送消息!\n"); } } } return 0; } 这些功能都比较简单,实现不难,都是书上的简单应用。实际上如果仅仅是实现上述功能,不必如此复杂,但是自己觉得初学时就应该把各个功能代码分开。 因为工作时,不会让你写万整个程序,而是把功能分给不同的人写。 笔者愚笨,刚开始接触UNIX网络编程,如有错误,或者BUG,可留言联系。