学习总结:因为前一段对LINUX –C的学习也对网络编程有一点的认识,通过这一次聊天室的制作,更增加对学习新知识的兴趣。写聊天室时主要遇到的
问题是
1.服务器实现并发功能(接受和发送)
2.实现多客户端连接服务器。
3.怎样识别客户端之间的差别与联系
4.实现多客户端之间的接受和发送。
问题解决方案
1.实现并发服务,我主要用了线程进行接收,通过接收的信息在识别创建发送线程。在服务器主函数中主要管理客户端的连接。
2.在主函数中连接客户端主要是用数组贮存接收成功后(accept函数)的标识符,这样每个客户端都可连接,并且客户端可区分。
3.我用接收成功后的标识符和客户端的用户名进行客户端识别。
4.服务器通过客户端发送过来的字符串进行识别,发送的是个人还是群聊。
这次写的比较简单,代码还可以进行完善和功能添加。
服务器: #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <string.h> #include <memory.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <error.h> #include <netinet/in.h> #include <arpa/inet.h> #include<termios.h> #define MAX_LINE 1024 #define MAX_CLIENT 15 char recvbuf[MAX_LINE]={0}; //传送内容缓冲区 int num=0; //客户端连接标记 char sendbuf[MAX_LINE]={0}; int client[MAX_CLIENT]; //FD_SETSIZE,1024是tcp最大连接数,client[FD_SETSIZE] 存放有数据请求的客户端; char name[15][1024]={0}; int FLACE=0; int findname(char *name1) { int i = 0; for(i=0;i<5;i++) { printf("name[%d]=%s ",i,name[i]); } printf("find_name:%s",name1); for (i = 0; i < MAX_CLIENT; i++) { if (client[i]!=-1&&(strcmp((name[i]), name1))==0) return i; } return -1; } void sendto_one(int *client_num) { char buf[1024]={0}; char recvname[20] = { 0 }; char *p = strtok(sendbuf + 3, " ");//TO:3个字符后取出 前的名字 printf("(p)=%sa ",p); strcpy(recvname, p); int sock= findname(recvname); if(sock==0) { memset(buf, 0,MAX_LINE); sprintf(buf,"此人没上线 "); send(client[*client_num],buf,strlen(buf),0); } printf("(sock=)%d ",sock); while(1) { if(sock!=-1&&num==1) { memset(buf, 0,MAX_LINE); sprintf(buf,"FPOM:%s %s",name[*client_num],sendbuf+4+strlen(p)+2); send(client[sock],buf,strlen(buf),0); printf("send success "); num=0; } } } void sendto_all(int *client_num) { int i,j; char buf[1024] = { 0 }; printf("send.buf=%s ",sendbuf); memset(buf, 0,MAX_LINE); sprintf(buf, "FPOM:%s %s",name[*client_num],sendbuf); j=0; printf("sendto_all11.buf=%s ",buf); for(i=0;i<15;i++) { printf("client[%d]=%d ",i,client[i]); } while(1) { while(j<10) { if(client[j]!=-1&&num==1) { printf("name[j]%s",name[j]); send(client[j],buf,MAX_LINE,0); } printf("send to kehu "); j++; } num=0; } } void recvwhole(int* client_num) { int n; pthread_t tid2,tid3; while(1) { memset(recvbuf, 0,MAX_LINE);//初始化数组 n=0; n=recv(client[*client_num],recvbuf,MAX_LINE,0); if(n>0) { printf("(recv.buf=)%s ",recvbuf); memset(sendbuf, 0,MAX_LINE);//初始化数组 strcpy(sendbuf,recvbuf); num=1; printf("(num=)%d, (sendbuf:) %s ",num,sendbuf); } if (!strncmp(sendbuf, "TO:",3)) { printf("发送个人 "); pthread_create(&tid2,NULL,(void*)sendto_one,(void*)client_num); pthread_detach(tid2); } if (!strncmp(sendbuf, "ALL ", 5)) { printf("发送群体 "); pthread_create(&tid3,NULL,(void*)sendto_all,(void*)client_num); pthread_detach(tid3); } } } int input_name(int *n) { int a,b; memset(sendbuf, 0,MAX_LINE); //sprintf(sendbuf,"请输入你的姓名:"); //a=send(client[*n],sendbuf,MAX_LINE,0); b=recv(client[*n],name[*n],MAX_LINE,0); printf("(name[%d]=)%s ",*n,name[*n]); if(b>0) {return 0;} else { input_name(n); } } void *pthread_fun(int * client_num) { if(input_name(client_num)) { perror("input name fail");exit(-1); } char *p; pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,(void*)recvwhole,/); pthread_detach(tid1); } int main(int argc,char *argv[]) { struct sockaddr_in addr;//保存客户端地址 socklen_t len; //保存客户端地址长度 struct sockaddr_in add2; int port=8800; char addr_p[INET_ADDRSTRLEN]; int i=0,ii; int lfd,cfd; //套接字 int a[15]; pthread_t tid1,tid2; //创建线程变量 bzero(&addr,sizeof(addr));//清空地址结构 addr.sin_family=AF_INET;//使用IP4 addr.sin_port=htons(port);//端口号 addr.sin_addr.s_addr=INADDR_ANY;//服务器可以接受任意地址 for(i=0;i<MAX_CLIENT;i++) { client[i]=-1;} //1 if((lfd=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("fail to socket");exit(1); } printf("创建套接字成功 "); //设置端口可重用 int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //将套接字绑定到服务器的网络地址上 //2 if(bind(lfd,(struct sockaddr*)&addr,sizeof(addr))==-1) { perror("fial to bind");exit(1); } printf("绑定地址套接字成功 "); //3 if (listen(lfd, 10) == -1) { perror("fail to listen"); exit(1); } printf("监听成功 "); i=0; while(i<MAX_CLIENT) { ii=i; len=sizeof(add2); client[i]=accept(lfd,(struct sockaddr*)&add2,&len); //printf(" **%d ",client[i]); printf("接受成功,i = %d ",i); printf("create thread "); a[i]=i; if(pthread_create(&tid1,NULL,(void*)pthread_fun,&a[i])!=0) { perror("create success");exit(-1); } pthread_detach(tid1); i++; if(ii<i) { inet_ntop(AF_INET,&addr.sin_addr,addr_p,sizeof(addr_p));////将客户端地址转换为字符串 printf("IP=%s,port=%d ",addr_p,ntohs(addr.sin_port)); }
客户端: #include<stdio.h> #include<unistd.h> #include<string.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #define MAX_LINE 1024 char buf[MAX_LINE]; int port=8800; char name[200]={0}; int FLACE=0; void fun_all(int sockfd) { char sendbuf[1024]={0}; sprintf(sendbuf,"ALL ",5); printf(" ");getchar(); printf("输入聊天内容: "); fgets(sendbuf+strlen(sendbuf),100,stdin); //scanf("%s",sendbuf+5); //sprintf(sendbuf+strlen(sendbuf)," "); printf("(all sendbuf)=%s ",sendbuf); if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0) { printf("send error ");close(sockfd);exit(1); } } void fun_one(int sockfd) { char sendbuf[1024] = {0}; char name3[20] ; printf("输入聊天对象:");getchar(); memset(name3,0,20); fgets(name3,20,stdin); printf("(name3) %s",name3); sprintf(sendbuf,"TO:%s ",name3); printf("输入聊天内容: "); fgets(sendbuf+strlen(sendbuf),100,stdin); //printf("(sendbuf)=%s ",sendbuf); //sprintf(sendbuf+strlen(sendbuf)," "); if(send(sockfd,sendbuf,strlen(sendbuf),0) <= 0) { printf("send err "); close(sockfd); exit(1); } } void menu() { printf("^^^^^^^^^^^^^^^^^^^^ "); printf("1.私聊模式(发送to) "); printf("2.群聊模式(发送all) "); printf("~~~~~~~~~~~~~~~~~~~~ "); } void *fun(int *sock) { int sockfd=*sock; int n; char *p,*q; char name2[20]={0}; while(1) { n=0; memset(buf,0,MAX_LINE);//初始化数组 n=recv(sockfd,buf,MAX_LINE,0); if(n>0) { printf(" 接受到:"); printf(" ************* %s****************** ",buf); } if(n<=0) { printf("recv failed "); exit(1); } } } int main(int argc,char *argv[]) { int l_fd;//套接字 struct sockaddr_in addr; char sendbuf[1024] = {0}; char str[6] = {0}; int n; pthread_t pid1; bzero(&addr,sizeof(addr)); addr.sin_family=AF_INET; inet_pton(AF_INET,"10.25.100.*",&addr.sin_addr); addr.sin_port=htons(port); if((l_fd=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("fail to creat socket");exit(1); } printf("创建套接字成功 "); if(connect(l_fd,(struct sockaddr *)&addr,sizeof(addr)) == -1) { perror("fail to connect");exit(1); } printf("connect success "); memset(name,0,20); printf("请输入你的姓名:"); scanf("%s",name); sprintf(sendbuf,name); //把格式化的数据写入某个字符串,"LOGIN %s " send(l_fd,sendbuf,strlen(sendbuf),0); //printf("sendbuf=%s ",sendbuf); pthread_create(&pid1,NULL,(void*)fun,(void*)&l_fd); pthread_detach(pid1); while(1) { menu(); memset(str,0,6); scanf("%s",str); if(!strcmp(str,"all")) { printf("群聊模式 "); fun_all(l_fd); continue; } else if(!strcmp(str,"to")) { printf("私聊模式 "); fun_one(l_fd); continue; } else printf("请重新输入:"); } wait(NULL); close(l_fd); return 0; } } return 0; }