
目录
TCP协议喵
723__01:使用select实现一个基于UDP的一对一即时聊天程序。
001:
002: TIMEWAI OR BUG
721作业:
01:在一对一聊天的基础上,使用select实现一对多的回显服务。(回显服务即接收到客户端发送的数据后,再回复给客户端)
一对一的喵:
一对多的服务器喵:
02:使用select编写聊天室程序:客户端和服务端使用tcp通信;服务端可以处理新客户端的连接和转发消息;客户端可以连入服务端并发送消息。
struct sockaddr struct sockaddr_in  -->   struct in_addr struct hostent   htonl()   htons()   ntohl()   ntohs() int inet_aton(const char* cp,struct in_addr * inp);  in_addr_t inet_addr(const char* cp);                       const char* inet_ntop(int af,const void* src,char* dst,socklen_t size); struct hostent * gethostbyname(const char* name);  client :socket——connect——recv/send——close      (one fd) server:socket——bind——listen——accept——recv/send——close         (listendfd)             (peerfd)  int socket (int domain,int type,int protocol); int bind (int sockfd,const struct sockaddr* addr ,socklen_t addrlen); int listen (int sockfd,int backlog); int connect  (int sockfd,const struct sockaddr*addr, socklen_t addrlen); int accept (int sockfd,struct sockaddr* addr, socklen_t addrlen); ssize_t recv ( int sockfd,void* buf,size_t buf,int flags); ssize_t send( int sockfd,void* buf,size_t buf,int flags);  int setsockopt(int sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));                           int level ,int opname,const void* optval,socklen_t optlen靓仔不想抄代码了呜呜,好困
————————client : socket connect while(1) close ————————server : socket bind listen accept send     //send是阻塞式函数 close     //第一次send可以正常执行,此时因为连接已经断开了,服务器会收到一个RST报文 //第二次send时,服务器会收到一个SIGPIPE信号 ,该信号的默认处理方式是终结进程。 //总结:client的连接关闭,会导致服务器进程奔溃,是一个不能接受的情况,因为服务器要服务其他的客户端。 ————————client : socket connect recv close ————————server : socket bind listen accept send    sleep()   send     //服务器往一个已经断开了的连接上继续发送数据,会造成什么影响?       close    //数据在发送时是字节流,不是一个个的数据包 //数据之间是没有边界的概念  =》 TCP粘包问题  ————————client :          socket connect recv    recv close ————————server : socket bind listen accept send   send            close     //recv的返回值为0的情况  ————————client :          socket connect recv    recv close ————————server : socket bind listen accept send      close #include  #define IP "192.168.235.128" #define PORT1 8080 #define PORT2 8081  struct sockaddr* addr_create(const char* ip,int  port ){      struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }  int main() {     struct sockaddr* addr=addr_create(IP,PORT1);     struct sockaddr* addr1=addr_create(IP,PORT2);      int sockfd=socket(AF_INET,SOCK_DGRAM,0);     if(sockfd==-1){error(1,errno,"socket");}      //addr1暴露一下?     int err=bind(sockfd,addr1,sizeof(*addr));     if(err==-1){error(1,errno,"bind");}      int epfd=epoll_create1(0);     struct epoll_event epev;     epev.events=EPOLLIN;     epev.data.fd=sockfd;     epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&epev);     epev.data.fd=STDIN_FILENO;//标准输入的文件描述符,通常为 0     epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&epev);      struct epoll_event epev_arr[2];     char buff[4096];       while(1){         int num=epoll_wait(epfd,epev_arr,2,-1);         for(int i=0;i #include  #define IP "192.168.235.128" #define IP1 "42.194.149.92" #define PORT1 8082 #define PORT2 13332  struct sockaddr* addr_create(const char* ip,int  port ){      struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }  int main() {     struct sockaddr* addr=addr_create(IP,PORT1);     struct sockaddr* addr1=addr_create(IP1,PORT2);      int sockfd=socket(AF_INET,SOCK_DGRAM,0);     if(sockfd==-1){error(1,errno,"socket");}      //addr暴露一下     /* int err=bind(sockfd,addr,sizeof(*addr)); */     /* if(err==-1){error(1,errno,"bind");} */      int epfd=epoll_create1(0);     struct epoll_event epev;     epev.events=EPOLLIN;     epev.data.fd=sockfd;     epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&epev);     epev.data.fd=STDIN_FILENO;//标准输入的文件描述符,通常为 0     epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&epev);      struct epoll_event epev_arr[2];     char buff[4096];       while(1){         int num=epoll_wait(epfd,epev_arr,2,-1);         for(int i=0;i 
//client.c #include  #define IP1 "192.168.235.128" #define IP2 "42.194.149.92" #define PORT1 8080 #define PORT2 13332  struct sockaddr* addr_create(const char* ip,int  port ){     struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }  int main() {     int sofd=socket(AF_INET,SOCK_STREAM,0);     if(sofd==-1){error(1,errno,"socket");}      struct sockaddr* addr=addr_create(IP1,PORT1);     int err=connect(sofd,addr,sizeof(*addr));     if(err==-1){error(1,errno,"connect");}     printf("connect sucess\n");      fd_set set;     FD_ZERO(&set);     char buff[100]={0};      while(1){         FD_SET(STDIN_FILENO,&set);         FD_SET(sofd,&set);         select(sofd+1,&set,NULL,NULL,NULL);          if(FD_ISSET(STDIN_FILENO,&set)){             memset(buff,0,sizeof(buff));             err=read(STDIN_FILENO,buff,sizeof(buff));             if(strcmp(buff,"byby\n")==0){break;}             send(sofd,buff,err-1,0);         }         if(FD_ISSET(sofd,&set)){             memset(buff,0,sizeof(buff));             err=recv(sofd,buff,sizeof(buff),0);             if(err==0){printf("byebye\n");break;}             printf("ret:  %d,recv:%s \n",err,buff);         }     }     close(sofd);     return 0; }  //server.c #include  #define IP1 "192.168.235.128" #define IP2 "42.194.149.92" #define PORT1 8080 #define PORT2 13332  struct sockaddr* addr_create(const char* ip,int  port ){     struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }  int main() {     int sofd=socket(AF_INET,SOCK_STREAM,0);     if(sofd==-1){error(1,errno,"socket");}      struct sockaddr* addr=addr_create(IP1,PORT1);     int err=bind(sofd,addr,sizeof(*addr));     if(err==-1){error(1,errno,"bimd");}     printf("bind sucess\n");     /* struct sockaddr_in*  addrin=(struct sockaddr_in*)addr; */     /* printf("%s,%d\n",inet_ntoa(addr->sin_addr), */     /*        sizeof((struct sockaddr_in*)addr.sin.port)); */     err=listen(sofd,1);     if(err==-1){error(1,errno,"listen");}      struct sockaddr_in addr2;     socklen_t len=sizeof(addr2);     int peerfd=accept(sofd,(struct sockaddr*)&addr2,&len);     printf("client :%s:%d has connect\n",inet_ntoa(addr2.sin_addr),            ntohs(addr2.sin_port));     // sofd--->peerfd      fd_set set;     FD_ZERO(&set);     char buff[100]={0};      while(1){         FD_SET(STDIN_FILENO,&set);         FD_SET(peerfd,&set);         select(peerfd+1,&set,NULL,NULL,NULL);          if(FD_ISSET(STDIN_FILENO,&set)){             memset(buff,0,sizeof(buff));             err=read(STDIN_FILENO,buff,sizeof(buff));             if(strcmp(buff,"byby\n")==0){break;}             send(peerfd,buff,err-1,0);         }         if(FD_ISSET(peerfd,&set)){             memset(buff,0,sizeof(buff));             err=recv(peerfd,buff,sizeof(buff),0);             if(err==0){printf("byebye\n");break;}             printf("ret:  %d,recv:%s \n",err,buff);         }     }     close(sofd);     return 0; }  #include  #define IP1 "192.168.235.128" #define IP2 "42.194.149.92" #define PORT1 8080 #define PORT2 13332  struct sockaddr* addr_create(const char* ip,int  port ){     struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }  int main() {     int sofd=socket(AF_INET,SOCK_STREAM,0);     if(sofd==-1){error(1,errno,"socket");}      struct sockaddr* addr=addr_create(IP1,PORT1);     int err=bind(sofd,addr,sizeof(*addr));     if(err==-1){error(1,errno,"bimd");}     printf("bind sucess\n");     /* struct sockaddr_in*  addrin=(struct sockaddr_in*)addr; */     /* printf("%s,%d\n",inet_ntoa(addr->sin_addr), */     /*        sizeof((struct sockaddr_in*)addr.sin.port)); */     err=listen(sofd,1);     if(err==-1){error(1,errno,"listen");}      struct sockaddr_in addr2;     socklen_t len=sizeof(addr2);     int peerfd=accept(sofd,(struct sockaddr*)&addr2,&len);     printf("client :%s:%d has connect\n",inet_ntoa(addr2.sin_addr),            ntohs(addr2.sin_port));     // sofd--->peerfd      fd_set set;     FD_ZERO(&set);     char buff[100]={0};      while(1){         FD_SET(STDIN_FILENO,&set);         FD_SET(peerfd,&set);         select(peerfd+1,&set,NULL,NULL,NULL);          if(FD_ISSET(STDIN_FILENO,&set)){             memset(buff,0,sizeof(buff));             err=read(STDIN_FILENO,buff,sizeof(buff));             if(strcmp(buff,"byby\n")==0){break;}             send(peerfd,buff,err-1,0);         }         if(FD_ISSET(peerfd,&set)){             memset(buff,0,sizeof(buff));             err=recv(peerfd,buff,sizeof(buff),0);             if(err==0){printf("byebye\n");break;}             printf("ret:  %d,recv:%s \n",err,buff);         }     }     close(sofd);     return 0; }  //server.c #include  #define IP1 "192.168.235.128" #define IP2 "42.194.149.92" #define PORT1 8080 #define PORT2 13332  //聊天室服务端 typedef struct conn_s{     int netfd;     int isalive; }conn_t;  struct sockaddr* addr_create(const char* ip,int  port ){      struct sockaddr_in* addr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));     memset(addr,0,sizeof(*addr));     addr->sin_family=AF_INET;     addr->sin_port=htons(port);     addr->sin_addr.s_addr=inet_addr(ip);     return (struct sockaddr*)addr; }   int main(int argc,char* argv[]) {     struct sockaddr* addr=addr_create(IP1,PORT1);      int sofd=socket(AF_INET,SOCK_STREAM,0);     if(sofd==-1){error(1,errno,"socket");}      bind(sofd,(struct sockaddr *)&addr,sizeof(addr));     listen(sofd,10);          //用于管理文件描述符集合,用于指示哪些文件描述符正在监听的 I/O 事件已经发生     fd_set set;//select 监听的集合     FD_ZERO(&set);     FD_SET(sofd,&set);          conn_t list[1024];     memset(list,0,sizeof(list));     int index;      while(1){         fd_set temp_set;//构建此次的监听合计         memcpy(&temp_set,&set,sizeof(set));//cp ser temp_set          select (10,&temp_set,NULL,NULL,NULL);          if(FD_ISSET(sofd,&temp_set)){             int netfd=accept(sofd,NULL,NULL);             list[index].isalive=1;             list[index].netfd=netfd;             FD_SET(netfd,&set);//增加监听              index++;         }          for(int i=0;isend  client                     for(int j=0;j