Linux/Unix IO多路复用之select网络编程(含源码)
前言
本章节是用基本的Linux/Unix基本函数加上select调用编写一个完整的服务器和客户端例子,可在Linux(ubuntu)和Unix(freebsd)上运行,客户端和服务端的功能如下:
客户端从标准输入读入一行,发送到服务端
服务端从网络读取一行,然后输出到客户端
客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
#include <unistd.h>#include <sys/types.h> /* basic system data types */#include <sys/socket.h> /* basic socket definitions */#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */#include <arpa/inet.h> /* inet(3) functions */#include <sys/select.h> /* select function*/ #include <stdlib.h>#include <errno.h>#include <stdio.h>#include <string.h> #define MAXLINE 10240 void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset); int main(int argc, char **argv){int servPort = 6888;int listenq = 1024; int listenfd, connfd;struct sockaddr_in cliaddr, servaddr; socklen_t socklen = sizeof(struct sockaddr_in);int nready, nread;char buf[MAXLINE];int clientSockFds[FD_SETSIZE]; fd_set allset, rset;int maxfd; listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0) { perror("socket error");return -1; } int opt = 1;if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt error"); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(servPort); if(bind(listenfd, (struct sockaddr*)&servaddr, socklen) == -1) { perror("bind error"); exit(-1); } if (listen(listenfd, listenq) < 0) { perror("listen error");return -1; } int i = 0;for (i = 0; i< FD_SETSIZE; i++) clientSockFds[i] = -1; FD_ZERO(&allset); FD_SET(listenfd, &allset); maxfd = listenfd; printf("echo server use select startup, listen on port %d\n", servPort); printf("max connection: %d\n", FD_SETSIZE); for ( ; ; ) { rset = allset; nready = select(maxfd + 1, &rset, NULL, NULL, NULL);if (nready < 0) { perror("select error");continue; }if (FD_ISSET(listenfd, &rset)) { connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &socklen);if (connfd < 0) { perror("accept error");continue; } sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); printf(buf, ""); for (i = 0; i< FD_SETSIZE; i++) {if (clientSockFds[i] == -1) { clientSockFds[i] = connfd;break; } }if (i == FD_SETSIZE) { fprintf(stderr, "too many connection, more than %d\n", FD_SETSIZE); close(connfd);continue; }if (connfd > maxfd) maxfd = connfd; FD_SET(connfd, &allset);if (--nready <= 0)continue; } handle(clientSockFds, maxfd, &rset, &allset); }} void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset) {int nread;int i;char buf[MAXLINE];for (i = 0; i< maxFds; i++) {if (clientSockFds[i] != -1) {if (FD_ISSET(clientSockFds[i], pRset)) { nread = read(clientSockFds[i], buf, MAXLINE);//读取客户端socket流 if (nread < 0) { perror("read error"); close(clientSockFds[i]); FD_CLR(clientSockFds[i], pAllset); clientSockFds[i] = -1;continue; }if (nread == 0) { printf("client close the connection\n"); close(clientSockFds[i]); FD_CLR(clientSockFds[i], pAllset); clientSockFds[i] = -1;continue; } write(clientSockFds[i], buf, nread);//响应客户端 有可能失败,暂不处理 } } } }
客户端
代码如下:
#include <unistd.h>#include <sys/types.h> /* basic system data types */#include <sys/socket.h> /* basic socket definitions */#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */#include <arpa/inet.h> /* inet(3) functions */#include <sys/select.h> /* select function*/ #include <stdlib.h>#include <errno.h>#include <stdio.h>#include <string.h> #define MAXLINE 10240#define max(a,b) ((a) > (b) ? (a) : (b))//typedef struct sockaddr SA; void handle(int sockfd); int main(int argc, char **argv){char * servInetAddr = "127.0.0.1";int servPort = 6888;char buf[MAXLINE];int connfd;struct sockaddr_in servaddr; if (argc == 2) { servInetAddr = argv[1]; }if (argc == 3) { servInetAddr = argv[1]; servPort = atoi(argv[2]); }if (argc > 3) { printf("usage: selectechoclient <IPaddress> <Port>\n");return -1; } connfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(servPort); inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr); if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connect error");return -1; } printf("welcome to selectechoclient\n"); handle(connfd); /* do it all */ close(connfd); printf("exit\n"); exit(0);} void handle(int connfd){ FILE* fp = stdin;char sendline[MAXLINE], recvline[MAXLINE]; fd_set rset; FD_ZERO(&rset);int maxfds = max(fileno(fp), connfd) + 1;int nread;for (;;) { FD_SET(fileno(fp), &rset); FD_SET(connfd, &rset); if (select(maxfds, &rset, NULL, NULL, NULL) == -1) { perror("select error");continue; } if (FD_ISSET(connfd, &rset)) {//接收到服务器响应 nread = read(connfd, recvline, MAXLINE);if (nread == 0) { printf("server close the connection\n");break; } else if (nread == -1) { perror("read error");break; }else {//server response write(STDOUT_FILENO, recvline, nread); } } if (FD_ISSET(fileno(fp), &rset)) {//标准输入可读 if (fgets(sendline, MAXLINE, fp) == NULL) {//eof exit break; } else { write(connfd, sendline, strlen(sendline)); } } } }
下载和编译
下载地址
编译和启动服务端
gcc selectechoserver.c -o selectechoserver
编译和启动客户端
gcc selectechoclient.c -o selectechoclient
Linux/Unix IO多路复用之select网络编程(含源码)相关推荐
- Linux IO多路复用之epoll网络编程(含源码)
前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...
- Linux IO多路复用之epoll网络编程,高并发的使用例子 (含源码)
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一行,然 ...
- Linux 学习数据专题【管理、编程、源码分析】——Linux相关图书选购指南
编辑推荐--Linux专题 http://www.china-pub.com/main/linux/linux_fengrui.htm Linux相关图书选购指南 本期特约作者 冯锐 (会员名:ph ...
- Linux下IO多路复用之select函数的使用
select函数的作用: 如果我们的程序里有两个需要阻塞的地方,例如要从服务器读数据,同时还要从键盘上读数据(若不采用阻塞而用查询的方式则大量占用系统资源).这个时候我们就有两处阻塞,你当然可以用多线 ...
- 电子词典的python3 结合网络编程项目实例源码
此次为第一版的python3 电子词典查询词汇,后期会继续跟进程序的交互以及优化 客户端: #2018.07.02 今天白天搞定# #客户端 服务端之间的连接依靠套接字socket 进程并发 # ...
- java 聊天机器人 源码_Alice聊天机器人源码及DEMO - 源码下载|Windows编程|网络编程|源代码 - 源码中国...
压缩包 : Alice聊天机器人源码及DEMO.rar 列表 Alice聊天机器人源码及DEMO/.classpath Alice聊天机器人源码及DEMO/.project Alice聊天机器人源码及 ...
- Python之进程+线程+协程(事件驱动模型、IO多路复用、select与epoll)
文章目录 一.事件驱动模型 二.IO多路复用 本篇文章是关于涉及网络编程与协程.进程之间结合的内容,其中事件驱动模型.IO多路复用.select与epoll的使用等方面的知识 一.事件驱动模型 1.事 ...
- 聊聊IO多路复用之select、poll、epoll详解
聊聊IO多路复用之select.poll.epoll详解 2016/04/22 · IT技术 · 1 评论 · epoll, IO多路复用, poll, select 分享到:0 本文作者: 伯乐在线 ...
- 【python】-- IO多路复用(select、poll、epoll)介绍及实现
IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...
- IO多路复用中select、poll、epoll之间的区别
本文来说下IO多路复用中select.poll.epoll之间的区别 文章目录 什么是IO多路复用 为什么有IO多路复用机制 同步阻塞(BIO) 同步非阻塞(NIO) IO多路复用(现在的做法) 3种 ...
最新文章
- FaceL:一个靠谱的开源人脸标注训练识别程序
- vs2005c语言连接mysql_VS2005连接MySQL C API
- 直播 | 北京邮电大学助理教授王啸:网络嵌入的最新进展
- arachni web mysql数据库_Web安全扫描工具Arachni
- OCR系列——总体概述
- electron 打包把node代理服务打包进去_专题:让C++给node做技术加持(三)编译electron本地模块踩坑记
- python常见安装
- php pcre回溯攻击,PHP利用PCRE回溯次数限制绕过某些安全限制 | 码农网
- Struts2返回Json数据(使用Struts2插件)
- 19【推荐系统4】DeeoCrossing
- Controller类中方法返回值详解
- python输入一个整数_Python中实现输入一个整数的案例
- 退出matlab环境的命令行,实验一 MATLAB环境及命令窗口的使用
- [推荐]白纸上的黑点和黑纸上的白点
- phpmailer 私密抄送_PHPMailer发匿名邮件及Extension missing: openssl的解决
- SpringMVC入门运行成功的实例(一)
- html网页结尾署名,书信署名及敬语常识(转摘)
- 谈谈区块链入门技能(二):以太坊区块链浏览器如何使用?
- 精伦r210的使用的源码
- mysql分表的原则_mysql分表规则(转)
热门文章
- java脚本计算器按钮无反应_2020年3月份最新计算机语言排行,20种语言争锋相对Java依旧飘逸...
- pid调节软件_三面大疆惨败,因为不懂PID的积分抗饱和
- redis cluster 分布式锁_Redis的分布式锁的实现原理
- esp8266等待上电同步_[网络篇]ESP8266-NonOS学习笔记(三)之TCP通信Serverlt;-gt;Client
- 19年PDYZ冬令营游记
- 转(static final 和final的区别)
- BGP消息格式-UPDATE
- 探秘综合布线产品质保问题
- 将Nokia 6300 Firmware升级到5.5
- CCIE学习(18)——HSRP、VRRP和GLBP