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
- Linux网络编程-select实现多点连接的回射
- Linux网络编程select模型的实现
- Linux网络编程select模型的实现
- Linux网络编程select模型的实现
- Linux网络编程(3)使用select处理多个连接的回射服务器
- linux 网络编程的Epoll Select
- linux网络编程之 select()的模型
- linux网络编程之 select()的模型
- Linux网络编程用select实现异步通讯聊天程序
- Linux网络编程echo简单示例2--select实现
- Linux网络编程:使用select函数实现socket 收发数据
- linux网络编程之用select函数实现io复用(基于TCP)引发的思考
- Linux 网络编程中的select
- Linux 网络编程中的select
- Linux 网络编程中的select
- Linux网络编程之select
- linux网络编程之select
- linux网络编程 select()函数
- android AccessibilityService解析
- I/O多路转接之epoll模型
- 银行有一个账户,有两个储户,分别向同一户存3000元,每次存一千,存3次, 每次存完打印账户余额
- Python3之生成器函数及表达式
- 关于日历取n天前日期
- Linux网络编程-select实现多点连接的回射
- noi 14:扫雷游戏地雷数计算
- 阿里云oss对象存储 js web直传中文件重命名和文件数量限制问题的解决
- Winodws环境搭建sbt
- JavaScript的学习(三)--条件语句
- 跨平台二维绘图程序(一)——前奏
- java获取当月天数,指定年月的天数,指定日期获取对应星期
- pl/sql配置远程数据库
- 有符号类型和无符号类型