Linux网络编程-select实现多点连接的回射
2017-08-02 10:21
405 查看
server.c
PS:
1 在debian 7上进行过简单测试,成功。
2 如果客户端或者服务器端用readn 和writen函数,则服务器端或客户端也必须用这个两个函数,否则不能正常回射。
#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); //选择IP setsockopt(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 1024 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); } 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 8ab9 (&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函数,则服务器端或客户端也必须用这个两个函数,否则不能正常回射。
相关文章推荐
- Linux网络编程-select实现多点连接的回射
- Linux网络编程-select实现多点连接的回射
- Linux网络编程select模型的实现
- Linux网络编程select模型的实现
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
- linux中使用select和epoll确定异步connect连接是否成功 标签: 网络编程服务器异步connectSO_ERRORsocket 2016-07-31 23:07 1008人阅读 评
- linux网络编程之socket(十一):套接字I/O超时设置方法和用select实现超时
- Linux socket网络编程之聊天室(三):select异步通讯实现
- linux网络编程之socket(十一):套接字I/O超时设置方法和用select实现超时
- Linux socket网络编程之聊天室(三):select异步通讯实现
- linux网络编程之socket(十一):套接字I/O超时设置方法和用select实现超时
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
- linux socket网络编程:fcntl select(多个客户端连接服务器端情形)
- linux socket网络编程:fcntl select(多个客户端连接服务器端情形)
- 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
- linux网络编程并发进程,select和epoll(一)
- Linux 网络编程基础---------------客户端/服务器的简单实现
- Linux下网络编程实现UDP
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现