8.19作业
1.项目:建立服务器和客户端(客户端发出的信息其他客户端接收,服务器发出的信息全部客户端接收)
服务器代码:
#include <25061head.h>#define SER_IP "192.168.109.126"
#define SER_PORT 8888typedef struct Node
{union{int data;int len;};char username[50];struct sockaddr_in addr;struct Node *next;
}*linklist;linklist creat_head()
{linklist head=(linklist)malloc(sizeof(struct Node));if(head==NULL){return NULL;}head->len=0;head->next=NULL;return head;
}linklist creat_node(int fd,const char* name,struct sockaddr_in addr)
{linklist s=(linklist)malloc(sizeof(struct Node));if(NULL==s){return NULL;}s->data=fd;strncpy(s->username,name,sizeof(s->username)-1);s->username[sizeof(s->username)-1]='\0';s->next=NULL;return s;
}int insert_rear(int fd,const char* name,struct sockaddr_in addr,linklist head)
{if(NULL==head){return -1;}linklist s=creat_node(fd,name,addr);if(NULL==s){return -1;}linklist p=head;while(p->next!=NULL){p=p->next;}p->next=s;head->len++;return 0;
}int delete_client(linklist head,int fd)
{if(NULL==head||NULL==head->next){return -1;}linklist prev=head;linklist curr=head->next;while(curr!=NULL){if(curr->data==fd){prev->next=curr->next;free(curr);head->len--;return 0;}prev=curr;curr=curr->next;}return -1;
}const char *find_username(linklist head,int fd)
{linklist p=head->next;while(p!=NULL){if(p->data==fd){return p->username;}p=p->next;}return "unknown";
}void broadcast(linklist head,char *msg,int exclude_fd)
{linklist p=head->next;while(p!=NULL){if(p->data!=exclude_fd){send(p->data,msg,strlen(msg),0);}p=p->next;}
}int main(int argc, const char *argv[])
{linklist head=creat_head();if(head==NULL){perror("creat_head error");return -1;}int sfd=socket(AF_INET,SOCK_STREAM,0);if(-1==sfd){perror("socket error");return -1;}printf("socket success sfd=%d\n",sfd);int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){perror("setsockopt error");return -1;}printf("端口号快速重用成功\n");struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(SER_PORT);sin.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success\n");if(listen(sfd,128)==-1){perror("listen error");return -1;}printf("listen success\n");struct sockaddr_in cin;socklen_t addrlen=sizeof(cin);char buf[256]="";fd_set readsfds;FD_ZERO(&readsfds);FD_SET(0,&readsfds);FD_SET(sfd,&readsfds);fd_set tempfds;int maxfd=sfd;while(1){tempfds=readsfds;int res=select(maxfd+1,&tempfds,NULL,NULL,NULL);if(res==-1){perror("select error");break;}else if(res==0){printf("time out\n");continue;}if(FD_ISSET(sfd,&tempfds)){int new_fd=accept(sfd,(struct sockaddr*)&cin,&addrlen);if(-1==new_fd){perror("accept error");continue;}char username_buf[50]={0};ssize_t name_len=recv(new_fd,username_buf,sizeof(username_buf),0);if(name_len<=0){perror("recv name error");close(new_fd);continue;}username_buf[name_len]='\0';if(insert_rear(new_fd,username_buf,cin,head)==0){printf("新客户端:%s(fd=%d)\n",username_buf,new_fd);char join_msg[256];snprintf(join_msg,sizeof(join_msg),"[系统]%s登录",username_buf);broadcast(head,join_msg,-1);}FD_SET(new_fd,&readsfds);if(new_fd>maxfd){maxfd=new_fd;}printf("[%s:%d] fd=%d username=%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),new_fd,username_buf);}//服务器向客户端发送信息if(FD_ISSET(0,&tempfds)){if(fgets(buf,sizeof(buf),stdin)==NULL){perror("fgets error");continue;}if(strlen(buf)==0){continue;}char system_msg[2048];snprintf(system_msg,sizeof(system_msg),"[系统公告]:%s",buf);broadcast(head,system_msg,-1);}for(int i=sfd+1;i<=maxfd;i++){if(FD_ISSET(i,&tempfds)){char rbuf[128]="";ssize_t res=recv(i,rbuf,sizeof(rbuf)-1,0);if(res==0){const char *username=find_username(head,i);printf("客户端%s(fd=%d)已下线\n",username,i);char leave[256];snprintf(leave,sizeof(leave),"[系统]:%s下线",username);broadcast(head,leave,i);close(i);FD_CLR(i,&readsfds);delete_client(head,i);if(i=maxfd){for(int j=maxfd-1;j>=sfd;j--){if(FD_ISSET(j,&readsfds)){maxfd=j;break;}}}continue;}if(res==-1){perror("recv error");close(i);FD_CLR(i,&readsfds);delete_client(head,i);continue;}rbuf[res]='\0';const char *sender_name=find_username(head,i);char fullmsg[512];snprintf(fullmsg,sizeof(fullmsg),"[%s]:%s",sender_name,rbuf);broadcast(head,fullmsg,i);}}}close(sfd);linklist curr=head->next;while(curr!=NULL){linklist next=curr->next;close(curr->data);free(curr);curr=next;}free(head);return 0;
}
客户端代码:
#include <25061head.h>#define SER_PORT 8888
#define SER_IP "192.168.109.126"int cfd;void *callback(void* arg)
{char buf[256];while(1){ssize_t res=recv(cfd,buf,sizeof(buf)-1,0);if(res<=0){printf("与服务器断开连接\n");close(cfd);exit(0);}buf[res]='\0';printf("%s\n",buf);fflush(stdout);}return NULL;
}int main(int argc, const char *argv[])
{if(argc!=4){printf("%s[用户名][服务器IP][端口号]\n",argv[0]);return -1;}const char *username=argv[1];const char *system_ip=argv[2];int port=atoi(argv[3]);cfd=socket(AF_INET,SOCK_STREAM,0);if(-1==cfd){perror("socket error");return -1;}printf("socket success cfd=%d\n",cfd);struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(port);sin.sin_addr.s_addr=inet_addr(system_ip);if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("connect error");return -1;}printf("连接成功\n");send(cfd,username,strlen(username),0);pthread_t thread=-1;if(pthread_create(&thread,NULL,callback,NULL)!=0){printf("线程创建失败\n");close(cfd);return -1;}pthread_detach(thread);char buf[256];while(1){if(fgets(buf,sizeof(buf),stdin)==NULL){break;}if(strcmp(buf,"quit")==0){break;}send(cfd,buf,strlen(buf),0);}close(cfd);return 0;
}
结果:
2.