深入学习linux socket编程之select

  很多天之前都说学习关于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423928.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jelinek-Merer与Absolute discounting 平滑方法

Jelinek-Merer Jelinek-Merer平滑方法的基本思想是利用低元n-gram模型对高元n-gram模型进行线性插值。 PML(wi∣wi−1)c(wi,wi−1)c(wi−1)P_{ML}(w_i|w_{i-1})\dfrac{c(w_i,w_{i-1})}{c(w_{i-1})}PML​(wi​∣wi−1​)c(wi−1​)c(wi​,wi−1​)​ c(wi,wi−1)c(w_i,w_{i-1}…

超级实用且不花哨的js代码大全

****************************************************************&#xff08;一&#xff09;常用元素&#xff0c;对象&#xff0c;事件&#xff0c;技巧事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture(); event.srcEl…

phpMyAdmin 配置

下载&#xff1a;http://downloads.sourceforge.net/project/phpmyadmin/phpMyAdmin/4.0.2/phpMyAdmin-4.0.2-all-languages.tar.bz2?rhttp%3A%2F%2Fsourceforge.net%2Fprojects%2Fphpmyadmin%2F&ts1370058054&use_mirrorncu 输入用户名和密码后点击“执行”&#xff…

三种平滑方法

为了理解《LETOR: A benchmark collection for research on learning to rank for information retrieval》中提出的数据特征中的三个&#xff1a;LMIR.ABS、LMIR.DIR、LMIR.JM的计算方法&#xff0c;我查阅了很多资料。前面一篇博客是理解。这一篇也是。这篇博客的内容来自《A…

控制台读写

program Project1;{$APPTYPE CONSOLE}varstr: string; beginWriteln(请输入&#xff1a;);Readln(str);Writeln(你输入的是&#xff1a; str);Readln; end.转载于:https://www.cnblogs.com/del/archive/2007/11/21/967013.html

基于Chromium构建Chrome WebBrowser for .net 控件(还有点心得体会)

http://blog.csdn.net/lllllllllluoyi/article/details/8540054 首先向360说句sorry&#xff0c;在2011年360极速浏览器出现的时候我去他们论坛里骂过。为什么要到歉呢&#xff0c;因为2012年我把我们公司使用IE WebBrowser改为Chrome控件了&#xff0c;中间遇到的辛酸使我明白…

我们“老实”么?

我们“老实”么&#xff1f; 不知道现在的人&#xff0c;对老实这个词语是怎样的看法。“聪明”的人应该觉得那是个贬义词吧&#xff0c;因为他们总是在利用那些他们认为的“老实”人&#xff0c;有好事的时候他们想到的是那些他们畏惧或者讨好自己的人&#xff0c;有麻烦的时候…

从决策树到xgboost(一)

文章目录1 决策树1.1决策树定义1.2信息增益1.3 信息增益的算法1.4 信息增益比2 决策树ID32.1 ID3树的构建2.2 决策树的剪枝2.2.1 损失函数定义与计算2.2.2 剪枝过程2.3 CART树2.3.1 CART回归树2.3.2 CART分类树2.3.3 CART树剪枝1 决策树 1.1决策树定义 决策树的基本组成&…

网络媒体的赢利模式

首先我们先确定几个概念&#xff0c;网络媒体本质上是媒体的一种&#xff0c;它具有媒体的一切共性&#xff0c;同时它的经营也具有媒体经营的一切共性&#xff0c;而媒体除网络媒体以外&#xff0c;我们把其余的统称为传统媒体&#xff0c;其中又把电视、电台和报刊称之为传统…

从决策树到xgboost(二)

文章目录3 集成学习4 Adaboost4.1 Adaboost算法4.1.1 初始化训练数据的起始权值分布4.1.2 对m个弱分类器m1,2,3...M4.1.3 构建弱分类器的线性组合4.1.4 得到最终的分类器5 Boosting5.1 加法模型5.2 前向分布算法6 提升决策树BDT6.1 BDT算法6.2 回归问题提升树7 梯度提升决策树G…

[伤了昨天的心 裂成碎片和沙一起飞]五香里脊

今晨3点挂的电话&#xff0c;6点睁开的眼。困到头痛&#xff0c;但还是烧了道肉菜。…**…**…**…**…**…**…**…*分隔 五香里脊*…**…**…**…**…**…**…**…五香里脊 材料&#xff1a;1&#xff0e;里脊肉、油、麻油。2&#xff0e;蒜末、辣椒末、水、生抽、老醋、糖、…

python 字符串format使用

python字符串的格式化输出 格式化字符串是程序设计语言中用于指定输出参数的格式化与相对位置的字符串参数。其中的转换说明用于把随后的对应一个或多个函数参数转换为相应的格式输出&#xff1a;格式化字符串中转换说明以外的其他字符原样输出。 1>>>"I like %s…

MOTOMAN-SV3X运动学建模验证图

以下是正解&#xff0c;逆解 结果 转载于:https://www.cnblogs.com/wqj1212/archive/2008/01/01/1022177.html

极客时间算法练习题总结

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 在极客时间《数据结构和算法之美》最后&#xff0c;王争老师加餐了7天训练内容&#xff0c;对每一部分需要掌握的数据结构与算法做了总结。现在我把这些题目放在一起&…

小程序·云开发实战 - 迷你微博

0. 前言 本文将手把手教你如何写出迷你版微博的一行行代码&#xff0c;迷你版微博包含以下功能&#xff1a; Feed 流&#xff1a;关注动态、所有动态发送图文动态搜索用户关注系统点赞动态个人主页使用到的云开发能力&#xff1a; 云数据库云存储云函数云调用没错&#xff0c;几…

看看自己08年的基金是否能赚钱

你的机器人已通过审核&#xff0c; 机器人名称&#xff1a;天才小猪仔-基金定投 机器人帐号&#xff1a;sharetop.cnhotmail.com 机器人地址&#xff1a; http://contest.xiaoi.com/listRobot.do?actionshowDetail&id61 欢迎进入 http://contest.xiaoi.com 为你的机器人…

spring mvc学习(60):ssm项目整合

SSM整合 建立springmvc项目&#xff0c;先跑起来&#xff0c;再整合spring和mybatis 一.SpringMVC建立 1.新建maven工程&#xff0c;安装tomcat 2.导入pom <!-- springmvc --><dependency><groupId>org.springframework</groupId><artifactId>…

回溯算法归纳

回溯算法解题思路回溯的两种思路题目描述按照思路1解决按思路2解决回溯的两种思路 看不同的解题方法&#xff0c;形成不同的思维。 先说结论。回溯解题思路1&#xff1a;是对可选择每个元素&#xff0c;采取不选择、选择两种策略&#xff0c;不断递归下去。最近看花花酱的视频…

Des与3Des加密解密

/// <summary>/// Des和3Des算法/// </summary>public class Des{/// <summary>/// Des加密/// </summary>/// <param name"pToEncrypt">明文</param>/// <param name"sKey">密钥</param>/// <returns…

Javascript中Date对象的使用

JavaScript 没有一个基本的日期数据类型&#xff0c;所以我们只能显式地创建Date对象。我们创建新的Date对象和创建String对象的方式是一样的&#xff0c;使用关键字new和Date构造函数。下面这行创建了一个包含当前日期和实践的Date对象&#xff1a;var todaysDate new Date()…