很多天之前都说学习关于select和poll的知识了,但是由于既要工作,又要准备论文。都忙不过来,今天终于能抽出一天的时间把select的相关知识和程序给实现了一遍。

  

  select系统调用是用来让我们的程序监视多个文件句柄(file descriptor)的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变。

Select函数的定义:

#include  <sys/types.h>

#include  <sys/times.h>

#include  <sys/select.h>

int select(nfds, readfds, writefds, exceptfds, timeout)

int nfds;

fd_set *readfds, *writefds, *exceptfds;

struct timeval *timeout;

   select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他 文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读写。当readfds或writefds中映象的文件可读或可写或超时,本次select()  就结束返回。程序员利用系统提供的宏FD_ISSET(int fd, fd_set *fdset) 在select()结束时便可判断哪一文件可读或可写。这样我们编写的socket只需要在有东西可读入或写的时候才进行操作。下面给出socket编程中select函数的通用范例:

...

int     sockfd, nRet;

fd_set  fdR;

struct  timeval timeout = ..;

...

for(;;) {

FD_ZERO(&fdR);

FD_SET(sockfd, &fdR);

switch ((nRet =select(sockfd + 1, &fdR, NULL, &timeout))) {

case -1:

error handled by u;

case 0:

timeout hanled by u;

default:

printf(“%d”,nRet);  //返回发生变化的句柄的个数

if (FD_ISSET(sockfd)) {  //先判断一下socket这外被监视//的句柄是否真的变成可读的了

now u read or recv something;

/* if sockfd is father and

server socket, u can now

accept() */

}

}

}

FD_ISSET(sockfd)就相当通知了sockfd可读。

下面是select的具体实现。主要是参考了faraway的关于select的例子,他的例子实现得真的非常的好,而且下面的评论也给出了很多改进的方法。把这个例子弄懂,那么你对select应该就掌握得差不多了。同时我还把socket通信的两个函数封装了一下,为了以后再写socket通信不再做同类重复的工作。一个是服务器端的建立socket的ServerBuildSocket()函数,还有一个是客户端的ConnectServer()函数。当然我这里的实现都是按照具体一个工程的实现的角度来写的,不再是像以前那样都集成在一个简单的main函数里面。这应该也算是我自己做的第一个从做工程角度去写的实现代码的吧。

config.h

#ifndef _CONFIG_H
#define _CONFIG_H//用于控制输出的#define _DEBUG
#ifdef _DEBUG
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...)
#endif   #endif

select_server.c

#include "socketlib.h"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define MYPORT 4444
#define BACKLOG 5
#define BUF_SIZE 200int fd_A[BACKLOG];
int conn_amount;int main()
{int nSocktfd, nNewSocktfd;int i,nRet,nMaxSock,nSockaddrLen;struct sockaddr_in client_addr;char szBuf[BUF_SIZE];fd_set fdRead;struct timeval tv;nSocktfd = ServerBuildSocket(MYPORT);if (nSocktfd < 0){TRACE("ServerBuildSocket faile.\n");exit(0);}conn_amount = 0;nSockaddrLen = sizeof(client_addr);nMaxSock = nSocktfd; while(1){FD_ZERO(&fdRead);FD_SET(nSocktfd,&fdRead);tv.tv_sec = 30;tv.tv_usec = 0;//add active connect to fd setfor (i = 0; i < BACKLOG; i++) {if (fd_A[i] != 0){FD_SET(fd_A[i],&fdRead);}}nRet = select(nMaxSock + 1, &fdRead, NULL, NULL, &tv);if (nRet < 0){TRACE("select failed.\n");break;}else if(nRet == 0){TRACE("timeout.\n");continue;}//check whether the connection have data to recieve for (i = 0; i < BACKLOG; i++){if (fd_A[i] && FD_ISSET(fd_A[i],&fdRead)){nRet = recv(fd_A[i],szBuf,sizeof(szBuf),0);if (nRet <= 0){TRACE("Client %d close\n",i);close(fd_A[i]);FD_CLR(fd_A[i],&fdRead);fd_A[i] = 0;conn_amount --;}else{if (nRet < BUF_SIZE)memset(&szBuf[nRet],'\0',1);TRACE("Client[%d] send: %s.\n",i,szBuf);}}}//for//check whether a new connection comesif (FD_ISSET(nSocktfd,&fdRead)){nNewSocktfd = accept(nSocktfd, (struct sockaddr *)&client_addr,&nSockaddrLen);if (nNewSocktfd <= 0){TRACE("accept failed.\n");continue;}if (conn_amount < BACKLOG -1){for(i = 0; i < BACKLOG; i++){if(fd_A[i] == 0){fd_A[i] = nNewSocktfd;conn_amount ++;break;}}TRACE("new connection client[%d] %s:%d\n", conn_amount,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));if (nNewSocktfd > nMaxSock){nMaxSock = nNewSocktfd;}}else{TRACE("max connections arrive,exit\n");send(nNewSocktfd,"bye",4,0);close(nNewSocktfd);continue;}}}//while//close all connectionsfor (i = 0; i < BACKLOG; i++){if (fd_A[i] != 0){close(fd_A[i]);}}exit(0);}

select_client.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "config.h"
#include "socketlib.h"#define MYPORT 4444int main()
{int nSockFd;int nLen;char szBuf[1024];nSockFd = ConnectServer("127.0.0.1",MYPORT);if (nSockFd < 0){TRACE("ConnectServer failed.\n");exit(0);}while(fgets(nSockFd, 1024, stdin) != NULL){if(send(nSockFd,szBuf,strlen(szBuf),0) <= 0){TRACE("send failed.\n");exit(0);}}close(nSockFd);exit(0);}

封装的函数:socketlib.h   socketlib.c

#ifndef _SOCKETLIB_H
#define _SOCKETLIB_Hint ServerBuildSocket(unsigned int nPort);
int ConnectServer(const char *szIp,int nPort);#endif

#include "socketlib.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int ServerBuildSocket(unsigned int port)
{//Build socket for server ,bind and listen the portint sock_fd,BACKLOG = 5;int nOptVal = 1;struct sockaddr_in server_addr;if ((sock_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){return -1; }if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,&nOptVal,sizeof(int)) == -1){return -2;}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){return -3;}if (listen(sock_fd,BACKLOG) == -1){return -4;}return sock_fd;}int ConnectServer(const char *szIp, int nPort)
{int nSockFd;int nAddrLen;struct sockaddr_in addr;if ((nSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1){return -1;}addr.sin_family = AF_INET;addr.sin_port = htons(nPort);if (inet_aton(szIp, &addr.sin_addr) < 0){return -2;}nAddrLen = sizeof(addr);if (connect(nSockFd,(struct sockaddr *)&addr, nAddrLen) == -1){return -3;}return nSockFd;
}

server的makefile:

server:select_server.o socketlib.o gcc -o server select_server.o socketlib.o
client:select_client.o socketlib.ogcc -o client select_client.o socketlib.o
select_server.o:select_server.c socketlib.hgcc -c select_server.c socketlib.h
select_client.o:select_client.c socketlib.hgcc -c select_client.c socketlib.h
socketlib.o:socketlib.c socketlib.hgcc -c socketlib.c socketlib.hclean:rm -f select_sever.o socketlib.o

转载于:https://www.cnblogs.com/Jason-Damon/archive/2013/04/18/3029385.html

深入学习linux socket编程之select相关推荐

  1. socket编程之select()

    转载自:http://www.cnblogs.com/ggzss/archive/2011/08/25/2153746.html Select在Socket编程中还是比较重要的,它能够监视我们需要监视 ...

  2. linux socket编程之TCP与UDP

    转:http://blog.csdn.net/gaoxin1076/article/details/7262482 TCP/IP协议叫做传输控制/网际协议,又叫网络通信协议 TCP/IP虽然叫传输控制 ...

  3. Linux网络编程之select

    使用select多路复用技术的非阻塞模型 select多路复用通常具有很好的跨平台性,也能提供不错的并发性能,但是在通常情况下有最大监听文件描述符的限制(通常1024),如果不需要达到C10K这种前端 ...

  4. 基于Linux的Socket编程之TCP全双工Server-Client聊天程序

    转载:http://blog.csdn.net/apollon_krj/article/details/53437764#0-tsina-1-58570-397232819ff9a47a7b7e80a ...

  5. Linux下socket编程之UDP简单实现

    本文实现一个简单的UDP小例子,来说明Linux下socket编程之UDP的简单实现.本文主要包括三个部分:服务器端的实现,客服端的实现和通信测试.实现的功能:客服端发送一条消息给服务器端,服务器端把 ...

  6. Linux下Socket编程之TCP应用

    现在,我们用前面所构建的socket类,重新设计<Linux下Socket编程之TCP Server端>中echo的服务器,然后设计客户端程序. echo服务器的工作原理很简单: 1.接收 ...

  7. Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解

    Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解 (1)sockaddr struct sockaddr { unsigned  short  sa_ ...

  8. linux c编程之fcntl

    fcntl可实现对指定文件描述符的各种操作,其函数原型如下: int fcntl(int fd, int cmd, ... /* arg */ ); 其中,操作类型由cmd决定.cmd可取如下值: F ...

  9. linux C编程之makefile

    linux C编程之makefile 目的:       基本掌握了 make 的用法,能在Linux系统上编程. 环境:       Linux系统,或者有一台Linux服务器,通过终端连接.一句话 ...

最新文章

  1. 用R语言 画条形图(基于ggplot2包)
  2. P2689 东南西北
  3. uva 11401思维+预处理
  4. Java连接Elasticsearch6.xxx 代码高亮显示篇四
  5. LaTeX调整目录的行距
  6. html语言中强调的ddr,DDR基础知识
  7. paip.c++ 常用类库attilax总结
  8. Windows7系统的70个小技巧
  9. 2020年阿里巴巴校招面试题及答案持续更新中~~~
  10. 两大主流存储架构介绍:软件定义存储与超融合
  11. 好用的识别植物的软件app合集分享,快码住了
  12. c语言个人所得税的打印思路,C语言编写一个计算个人所得税的程序,要求输入收入金额,能够输...
  13. java当单据变化触发,UAP开发(NC63)遇到的错误记录
  14. GSMA RCS标准的演变
  15. 「软件测试4」一文详解四大典型的白盒测试方法
  16. WebMatrix开发ASP.NET试用手记[转帖]
  17. Tomcat Ajp(CVE-2020-1938) 漏洞复现与修复
  18. JAVA计算机毕业设计智能导诊系统Mybatis+源码+数据库+lw文档+系统+调试部署
  19. 嵌入式开发--RS-485通讯的问题
  20. python数组转置和换轴_Numpy基础:数组转置和轴对换

热门文章

  1. CM3计算板安装硬件时钟DS3231
  2. JavaScript 监听手机端的touch滑动事件(滑动手势)
  3. python 学习资源推荐
  4. Python 问题--encode、decode及shell中文输出
  5. 信号量与令牌桶_限流的4种方式令牌桶实战
  6. if else if else语句格式_你还在用if/else吗?
  7. 「BZOJ2654」tree
  8. [19/03/16-星期六] 常用类_Date时间类DateFormat类
  9. 为什么MySQL数据库要用B+树存储索引
  10. PHP字符串函数大全