客户端
#include <myhead.h>
//创建结构体存储用户信息
struct User
{char tape;char username[32];char msg[1024];
};int main(int argc, const char *argv[])
{//创建套接字与服务器进行通信int sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return -1;}//绑定//填充服务器结构体数据struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(8888);sin.sin_addr.s_addr=inet_addr("192.168.125.86");char username[32]="";struct User user;strcpy(&user.tape,"L");//创建容器存储文件标识符fd_set readfds,tempfds;//清空容器FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(sfd,&readfds);int maxfd=sfd;while(1){tempfds=readfds;int res=select(maxfd+1,&tempfds,NULL,NULL,NULL);if(res==-1){perror("select error");return -1;}for(int i=0;i<=maxfd;i++){if(!FD_ISSET(i,&tempfds)){continue;} //向服务器读取消息else if(sfd==i){if(user.tape=='L'){//向服务器发送数据(用户结构体)printf("请输入登录用户>>>");scanf("%s",username);strcpy(user.username,username);if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("connect error");return -1;};//发送只有用户名和结构类型send(sfd,&user,sizeof(user),0);user.tape='C';}else if(user.tape=='C'){char Msg[2046]="";int len=recv(sfd,Msg,sizeof(Msg),0);if(len>=0){printf("%s",Msg);}else if(len==-1){perror("recv error");}}}//向服务器发送数据else if(i==0&&user.tape=='C'){char msg[1024]="";//向服务器发送数据(用户结构体)scanf("%s",msg); strcpy(user.msg,msg);if(strcmp(user.msg,"quit")==0){user.tape='Q';send(sfd,&user,sizeof(user),0);goto A;}send(sfd,&user,sizeof(user),0);}}}
A:close(sfd);return 0;
}
服务器端
#include <myhead.h>
struct userdata
{char tape;char username[32];char msg[1024];
};int main(int argc, const char *argv[])
{//创建套接字文件与客户端连接int sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket error");return -1;}signal(SIGPIPE, SIG_IGN);//绑定服务器信息//填充服务器信息struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(8888);sin.sin_addr.s_addr=inet_addr("192.168.125.86");socklen_t ssocklen=sizeof(sin); //重新启用端口int resue=1;setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&resue,sizeof(resue));//绑定if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return -1;}char mbuf[2048]="";//监听if(listen(sfd,168)==-1){perror("listen error");return -1;}//定义容器接收对端地址信息结构体struct sockaddr_in cin; socklen_t socklen=sizeof(cin);int newfd=-1;char sbuf[128]="";//创建容器存储文件描述符fd_set readfds,tempfds;//清空容器FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(sfd,&readfds);int maxfd=sfd;struct sockaddr_in cin_arr[1024];while(1){//保留容器tempfds=readfds;int res=select(maxfd+1,&tempfds,NULL,NULL,NULL);// printf("res=%d\n",res);if(res==-1){perror("select error");return -1;}else if(res==0){printf("TIME OUT\n");return -1;}for(int i=0;i<=maxfd;i++){struct userdata Users;char Tape=Users.tape; if(!FD_ISSET(i,&tempfds)){continue;}else if(i==sfd) //表示sfd触发了事件{newfd=accept(sfd,(struct sockaddr*)&cin,&socklen);if(newfd==-1){perror("accept error");return -1;}//服务器显示用户上线,并且广播给其他用户recv(newfd,&Users,sizeof(struct userdata),MSG_DONTWAIT);memset(Users.msg,0,sizeof(Users.msg));Tape=Users.tape; //更新maxfdif(newfd>maxfd){ maxfd=newfd;}if(Tape=='L'){//将用户信息存储char str[128]="";sprintf(str,"用户[%s]已上线\n",Users.username);printf("%s",str);for(int j=4;j<=maxfd;j++){if(j==newfd){continue;}send(j,str,sizeof(str),0);}}//将客户端放入数组FD_SET(newfd,&readfds);tempfds=readfds;cin_arr[newfd]=cin;break;}else if(i==0){fgets(sbuf,sizeof(sbuf),stdin);sbuf[strlen(sbuf)-1]=0;printf("触发键盘输入\n");char ssbuf[1024]="";sprintf(ssbuf,"服务器发来消息:%s\n",sbuf);for(int k=4;k<=maxfd;k++){send(k,ssbuf,strlen(ssbuf),0);}}else{//与客户端进行数据收发//定义一个结构体存储客户端发来的正文recv(i,&Users,sizeof(struct userdata),MSG_DONTWAIT);Tape=Users.tape;printf("%c\n",Tape);//接收客户端发来的数据if(Tape=='C'){//创建数组char mbuf[2046]="";sprintf(mbuf,"用户[%s]发送消息:%s\n",Users.username,Users.msg);printf("%s\n",mbuf);for(int j=4;j<=maxfd;j++){if(j==i){continue;}send(j,mbuf,sizeof(mbuf),0);}}else if(Tape=='Q'){//创建数组char msg[1024]="";sprintf(msg,"用户[%s]已下线\n",Users.username);printf("%s\n",msg);for(int j=4;j<=maxfd;j++){if(j==i){continue;}send(j,msg,sizeof(msg),0);}//关闭套接字close(i);//将当前文件描述符从容器中移除FD_CLR(i,&readfds);//更新maxfdfor(int j=maxfd;j>=0;j--){if(FD_ISSET(j,&readfds)){maxfd=j;break;}}continue;} }}}return 0;
}