Linux网络编程-select实现多点连接的回射

来源:互联网 发布:linux和unix的关系 编辑:程序博客网 时间:2024/06/05 01:18

server.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <errno.h>#define MAX_LOGIN 20     //设置客户端连接的最大数量#define BUFLEN 1024      //设置缓存的大小#define PORT 5000        //设置电脑端口ssize_t readn(int fd,void *buf,size_t count);ssize_t writen(int fd,void *buf,size_t count);void ehandle(char *mesg);int main(){int listenfd,connfd;struct sockaddr_in seraddr,cliaddr;int addrlen = 0;int nread = 0;char readbuf[BUFLEN];int opt = 1;fd_set rfds,readfds;int maxfd,nready,i;int clifd[FD_SETSIZE];if(-1 == (listenfd = socket(AF_INET,SOCK_STREAM,0)))   //生成监听套接字  ehandle("socket");bzero(&seraddr,sizeof(struct sockaddr_in));     //清零seraddr.sin_family = AF_INET;                   //选择IPv4协议seraddr.sin_port = htons(PORT);                  //选择5000端口seraddr.sin_addr.s_addr = htonl(INADDR_ANY);     //选择IPsetsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));  //端口重用,避免因为端口处于time_wait状态而不能够bind成功(同一端口)if(-1 == bind(listenfd,(struct sockaddr *)&seraddr,sizeof(struct sockaddr))) //端口和套接字绑定  ehandle("bind");if(-1 == listen(listenfd,MAX_LOGIN))    //开始监听  ehandle("listen");for(i = 0;i < FD_SETSIZE-1;i++)          //用一组数组保存客户端套接字,FD_SETSIZE为select所能监听的最大数量,监听套接字占了一个{clifd[i] = -1;}FD_ZERO(&rfds);FD_ZERO(&readfds);FD_SET(listenfd,&readfds);maxfd = listenfd;while(1){rfds = readfds;               //保险do{nready = select(maxfd +1,&rfds,NULL,NULL,NULL);}while(nready < 0 && EINTR == errno);  //避免因为其他中断引起select异常if(-1 == nready)  ehandle("select");if(FD_ISSET(listenfd,&rfds))             //处理监听到的客户端套接字{addrlen = sizeof(struct sockaddr);if(-1 == (connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&addrlen)))  ehandle("accept");printf("Connect IP:%s;PORT :%d\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));for(i = 0;i < FD_SETSIZE;i++){if(clifd[i] < 0)              //找到一个空的组员{clifd[i] = connfd;     //存储新的客户端套接字FD_SET(connfd,&readfds); //加入select监听序列if(connfd > maxfd)       //更新maxfd  maxfd = connfd;break;}}if(--nready <=0)                 //nready 减一,优化程序  continue;}for(i = 0;i <FD_SETSIZE;i++)           //循环查找被激活的客户端套接字,处理客户端的请求{if(clifd[i] > 0)  if(FD_ISSET(clifd[i],&rfds))  //因为用了两个集合,rfds和readfds,而这里一定要用rfds,错了就会只能与第一个链接成功的客户端通信。  {  memset(readbuf,0,sizeof(readbuf));  //清空缓存  connfd = clifd[i];  nread = readn(connfd,readbuf,sizeof(readbuf)); //读取客户端发来的字符串  if(-1 == nread)ehandle("readn");  else if(0 == nread)                         //客户端关闭处理  {  printf("client closed!\n");  clifd[i] = -1;                    //清空该组员,以便能够存储新的客户端套接字  FD_CLR(connfd,&readfds);          //从select监听序列中清除  close(connfd);                    //关闭该客户端套接字  }  else                                      //正常处理  {  printf("Receive %s",readbuf);  if(-1 == writen(connfd,readbuf,sizeof(readbuf)))   //把收到的字符串回射给客户端ehandle("writen");  }  if(--nready <= 0)                           //nready 减一,如果不为零,则继续处理其他的,同时被激活的客户端break;  }}}close(listenfd);return 0;}void ehandle(char *mesg)   //错误处理{perror(mesg);exit(1);}ssize_t readn(int fd,void *buf,size_t count)               //  读取固定字节数函数,避免粘包问题,这种处理方式效率不高{unsigned int nleft = count;int nread = 0;char *pbuf = (char*)buf;while(nleft > 0){nread = read(fd,pbuf,count);if(-1 == nread){if(EINTR == errno)  continue;return -1;}else if(0 == nread)  break;nleft -= nread;pbuf += nread;}return (count - nleft);}ssize_t writen(int fd,void *buf,size_t count)     //写入固定字节数函数,避免粘包问题,这种处理方式效率不高{unsigned int nleft = count;int nwrite = 0;char *pbuf = (char *)buf;while(nleft > 0){nwrite = write(fd,pbuf,count);if(-1 == nwrite){if(EINTR == errno)  continue;return -1;}else if(0 == nwrite)  continue;nleft -= nwrite;pbuf += nwrite;}return (count - nleft);}
client.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <netinet/in.h>#define PORT 5000#define IP "127.0.0.1"#define BUFLEN 1024void ehandle(char *mesg){perror(mesg);exit(1);}ssize_t readn(int fd,void* buf,size_t count){unsigned int nleft = count;int nread = 0;char *pbuf = (char *)buf;while(nleft > 0){nread = read(fd,pbuf,count);if(-1 == nread){if(EINTR == errno)  continue;return -1;}else if (0 == nread)  break;nleft -= nread;pbuf += nread;}return (count -nleft);}ssize_t writen(int fd,void *buf,size_t count){unsigned int nleft = count;int nwrite = 0;char *pbuf = (char *)buf;while(nleft > 0){nwrite = write(fd,pbuf,count);if(-1 == nwrite){if(EINTR == errno)  continue;return -1;}else if(0 == nwrite)  continue;nleft -= nwrite;pbuf += nwrite;}return (count - nleft);}int main(){int myfd;struct sockaddr_in seraddr;char strbuf[BUFLEN];int nread,nwrite;int maxfd;int nready = 0;fd_set readfds;if(-1 == (myfd = socket(AF_INET,SOCK_STREAM,0)))  ehandle("socket");bzero(&seraddr,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(PORT);//seraddr.sin_addr.s_addr = inet_addr(IP);inet_pton(AF_INET,IP,&seraddr.sin_addr,sizeof(struct in_addr));if(-1 == connect(myfd,(struct sockaddr*)&seraddr,sizeof(struct sockaddr)))  ehandle("connect");FD_ZERO(&readfds);while(1){FD_SET(STDIN_FILENO,&readfds);FD_SET(myfd,&readfds);maxfd = myfd;nready = select(maxfd + 1,&readfds,NULL,NULL,NULL);if(-1 == nready)  ehandle("select");else if(0 == nready)  continue;else{if(FD_ISSET(STDIN_FILENO,&readfds)){memset(strbuf,0,BUFLEN);fgets(strbuf,BUFLEN,stdin);nwrite = writen(myfd,strbuf,BUFLEN);if(-1 == nwrite)  ehandle("writen");}if(FD_ISSET(myfd,&readfds)){memset(strbuf,0,BUFLEN);nread = readn(myfd,strbuf,BUFLEN);if(-1 == nread)  ehandle("readn");else if(BUFLEN != nread){printf("Server ending!\n");break;}printf("Receive :%s",strbuf);}}}/*while(1){memset(strbuf,0,BUFLEN);fgets(strbuf,BUFLEN,stdin);nwrite = writen(myfd,strbuf,BUFLEN);if(-1 == nwrite)  ehandle("writen");memset(strbuf,0,BUFLEN);nread = readn(myfd,strbuf,BUFLEN);if(-1 == nread)  ehandle("readn");else if(BUFLEN != nread){printf("server ending!\n");break;}printf("Receive :%s\n",strbuf);}*/close(myfd);return 0;}


PS:

1 在debian 7上进行过简单测试,成功。

2 如果客户端或者服务器端用readn 和writen函数,则服务器端或客户端也必须用这个两个函数,否则不能正常回射。

阅读全文
0 0
原创粉丝点击