前言

本章节是用基本的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网络编程(含源码)相关推荐

  1. Linux IO多路复用之epoll网络编程(含源码)

    前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...

  2. Linux IO多路复用之epoll网络编程,高并发的使用例子 (含源码)

    本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一行,然 ...

  3. Linux 学习数据专题【管理、编程、源码分析】——Linux相关图书选购指南

    编辑推荐--Linux专题  http://www.china-pub.com/main/linux/linux_fengrui.htm Linux相关图书选购指南 本期特约作者 冯锐 (会员名:ph ...

  4. Linux下IO多路复用之select函数的使用

    select函数的作用: 如果我们的程序里有两个需要阻塞的地方,例如要从服务器读数据,同时还要从键盘上读数据(若不采用阻塞而用查询的方式则大量占用系统资源).这个时候我们就有两处阻塞,你当然可以用多线 ...

  5. 电子词典的python3 结合网络编程项目实例源码

    此次为第一版的python3 电子词典查询词汇,后期会继续跟进程序的交互以及优化 客户端: #2018.07.02  今天白天搞定# #客户端   服务端之间的连接依靠套接字socket 进程并发 # ...

  6. java 聊天机器人 源码_Alice聊天机器人源码及DEMO - 源码下载|Windows编程|网络编程|源代码 - 源码中国...

    压缩包 : Alice聊天机器人源码及DEMO.rar 列表 Alice聊天机器人源码及DEMO/.classpath Alice聊天机器人源码及DEMO/.project Alice聊天机器人源码及 ...

  7. Python之进程+线程+协程(事件驱动模型、IO多路复用、select与epoll)

    文章目录 一.事件驱动模型 二.IO多路复用 本篇文章是关于涉及网络编程与协程.进程之间结合的内容,其中事件驱动模型.IO多路复用.select与epoll的使用等方面的知识 一.事件驱动模型 1.事 ...

  8. 聊聊IO多路复用之select、poll、epoll详解

    聊聊IO多路复用之select.poll.epoll详解 2016/04/22 · IT技术 · 1 评论 · epoll, IO多路复用, poll, select 分享到:0 本文作者: 伯乐在线 ...

  9. 【python】-- IO多路复用(select、poll、epoll)介绍及实现

    IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...

  10. IO多路复用中select、poll、epoll之间的区别

    本文来说下IO多路复用中select.poll.epoll之间的区别 文章目录 什么是IO多路复用 为什么有IO多路复用机制 同步阻塞(BIO) 同步非阻塞(NIO) IO多路复用(现在的做法) 3种 ...

最新文章

  1. Windows消息:怎样使用RegisterWindowMessage注册消息
  2. 如何用web3.js在以太坊区块链上保存数据?
  3. 第七届蓝桥杯决赛JavaC组真题——详细答案对照(完整版)
  4. IntelliJ IDEA for Mac自定义动态代码模板快捷键(Live Templates Shortcut)
  5. python支付程序源码_支付宝推出新活动,Python脚本能让你赚的更多!(附源码)...
  6. Spring 三层架构
  7. Python实战从入门到精通第十三讲——返回多个值的函数
  8. 企业级私有registry Harbor通过https访问的详细配置
  9. 直接获取Program Files目录的API
  10. 2021-08-20 Redis 基本类型:string set sortedSet Hash List
  11. 【陷波滤波器】陷波滤波器设计与matlab仿真以及在PID控制器中的应用
  12. QCC3020/QCC3040 TWS耳机按键切换EQ,APP切换EQ功能实现
  13. 怎么查看自己宽带是公网ip还是内网ip?
  14. 【Ubuntu】解决ubuntu无法上网问题
  15. AVB之镜像的签名及验证签名详解
  16. 超微A+ Server 4124GS-TNR做主板集成RAID
  17. 11个好玩有趣的网站,一打开就停不下来
  18. java des 中文乱码_网络上DesUtil.java关于汉字加密解密出现乱码的问题
  19. python闭包,自由变量
  20. 四川师范大学Java期末_四川师范大学2008-2009第一学期常微分方程期末试题A英文版(含答案)精选.pdf...

热门文章

  1. pid调节软件_三面大疆惨败,因为不懂PID的积分抗饱和
  2. 奥鹏2019计算机应用基础1,奥鹏东师2019年秋季(计算机应用基础)离线考核(仅供参考).docx...
  3. 算法知识点——(4)降维
  4. windows10强制删除文件_如何恢复按下Shift + DELETE键永久删除的文件和资料夹?
  5. Linux命令行截屏,Scrot:Linux 命令行截屏工具
  6. edger多组差异性分析_edgeR基因表达差异分析
  7. 泛函密度 matlab,【讨论】密度泛函理论中“密度”究竟指什么 - 计算模拟 - 小木虫 - 学术 科研 互动社区...
  8. 蒙文字体怎么安装_蒙文搜索APP内置键盘布局图
  9. 完成的定义 Definition of Done
  10. salt-API基本验证命令