对于socket 通信,大家很多都用的单线程通信。同时只能监听一个端口,只能响应一个服务,select的方式可以解决多个socket 被连接的问题。一次可以分配多个资源,只要一个连接便可以进行通信。在网络已经有很多的select 的例子。不过很多例子没有真正体现到select的精妙之处。此函数主要是对多个文件描述符进行监听,直到某一个或者多个被连接。

  首先我们介绍fd_set这个结构:

  fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。fd_set集合可以通过一些宏由人为来操作,比如清空集合 FD_ZERO(fd_set *),将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set *),将一个给定的文件描述符从集合中删除FD_CLR(int ,fd_set*)。

  在select使用这个结构之前,我们需要调用FD_SET,设置对应socket的标志位,网络生很多的例子错误就在此,这里必须要绑定多个socket才是真正体会了select的多fd监听。而且不能随意指定,比如FD_SET(0,XX),这样的fd实际已经被系统占用了。在select成功返回后检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。进而根据对应的fd进行读写操作。不多说,直接粘贴代码:

 #include <iostream>
#include <sys/times.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) static int listen_socket(int port)
{
sockaddr_in s_in;
int s;
int yes;
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -)
{
cout<<"socket error"<<strerror(errno)<<endl;
return -;
}
yes = ;
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&yes,sizeof(yes)) == -)
{
cout<<"setsockopt error"<<strerror(errno)<<endl;
close(s);
return -;
} memset(&s_in, , sizeof(s_in));
s_in.sin_port = htons(port);
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(s,(sockaddr*)&s_in, sizeof(s_in)) == -)
{
cout<<"bind error"<<strerror(errno)<<endl;
close(s);
return -;
}
listen(s,);
cout<<"socket -> setsockopt-> bind->listen"<<port<<endl;
return s;
} int main(int argi, char* args[])
{
int h, h1;
int fd1 = -, fd2 = -; if(argi != )
{
cout<<"Usage server listen_port1 listen_port2"<<endl;
exit(-); } int listen_port1 = atoi(args[]);
fd1 = listen_socket(listen_port1);
int listen_port2 = atoi(args[]);
fd2 = listen_socket(listen_port2);//这里是建立了两个socket:cyjwdm0503
if(fd1==- || fd2==-)
{
exit(-);
}
for(;;)
{
int r, nfds = ;
fd_set rfd,sfd; FD_ZERO(&rfd);
FD_ZERO(&sfd);
FD_SET(fd1, &rfd);//绑定对应的两个socket
FD_SET(fd2,&rfd); int maxnum = max(, fd1);
maxnum = max(fd2, maxnum);
cout<<"maxnum:"<<maxnum<<"\t"<<h<<endl; r = select(maxnum+, &rfd, &sfd, NULL, NULL);//select的参赛为rfd,最大值为socket+1
if( r == - && errno == EINTR)
{
cout<<strerror(errno)<<endl;
continue;
}
if( r == -)
{
cout<<"select error"<<strerror(errno)<<"\t"<<errno<<endl;
return -;
} // for(int index=1; index<=5; index++)
{
int select_fd = ;
if(FD_ISSET(fd1,&rfd))
select_fd = fd1;
else if(FD_ISSET(fd2,&rfd))
select_fd = fd2;
else
select_fd = -;
if(select_fd != -)
{
cout<<"select retrun fd"<<select_fd<<endl;
sockaddr_in accept_addr;
socklen_t le = sizeof(accept_addr);//注意在accept时候的sockaddr_in 长度要初始化
int acc = accept(ddd, (sockaddr*)&accept_addr, &le); cout<<"accept port"<<accept_addr.sin_port<<endl; if(- == acc)
{
cout<<"accept error"<<strerror(errno)<<endl;
return -;
}
char buffer[] = "";
int ret = recv(acc, buffer, sizeof(buffer),);
if(ret <= )
{
cout<<"client close:"<<strerror(errno)<<"\t"<<errno<<endl;
}
else
{
cout<<"buffer from client:"<<buffer<<endl;
} }
else
cout<<"select_fd = -1"<<endl;
}
cout<<"for over"<<endl; }
}

  select 在监听对应的socket的rfd集合时,如果有对应的客户端链接两个socket之中的某一个,select 边能够返回对应的信息,然后调用FD_ISSET,获取对应被链接的socket ,进行accept ,收发信息。

  下面为客户端的示例代码:

 #include <iostream>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h> using namespace std; int main(int argi, char* args[])
{
if( argi<)
{
cout<<args[]<<"\t"<<"host port msg..."<<endl;
return -;
}
sockaddr_in s_in;
memset(&s_in, , sizeof(s_in));
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = inet_addr("127.0.0.1");//(args[1]);
s_in.sin_port = htons(atoi(args[])); cout<<"port"<<"\t"<<args[]<<endl;
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if( s == -)
{
cout<<"socket error"<<strerror(errno)<<endl;
} socklen_t length = sizeof(sockaddr_in);
if(- == connect(s, (sockaddr*)&s_in, length))
{
cout<<"connect error"<<strerror(errno)<<endl;
close(s);
return -;
}
for(;;)
{
char buffer[];
if(strcmp(args[2],"q")==)
break;
ssize_t size = send(s, buffer, strlen(buffer),);
cout<<"socket num:"<<s<<endl;
   sprintf(buffer,"%s%s",args[2],"www.cnblogs.com/cyjwdm0503");
size = send(s,args[],strlen(args[]),);
if( - == size)
{
cout<<"write error"<<strerror(errno)<<endl;
close(s);
return -;
}
}
close(s); }

虽然这里是以Linux为示例,Windows和这个也类似的,转载请注明来源地址http://www.cnblogs.com/cyjwdm0503

上面如果有问题,请最好留言给我,大家交流。

socket 通信之select的更多相关文章

  1. socket通信中select函数的使用和解释

    select函数的作用: select()在SOCKET编程中还是比较重要的,可是对于初学SOCKET的人来说都不太爱用select()写程序,他们只是习惯写诸如 conncet().accept() ...

  2. Linux Network IO Model、Socket IO Model - select、poll、epoll

    目录 . 引言 . IO机制简介 . 阻塞式IO模型(blocking IO model) . 非阻塞式IO模型(noblocking IO model) . IO复用式IO模型(IO multipl ...

  3. JAVA基础知识之网络编程——-基于NIO的非阻塞Socket通信

    阻塞IO与非阻塞IO 通常情况下的Socket都是阻塞式的, 程序的输入输出都会让当前线程进入阻塞状态, 因此服务器需要为每一个客户端都创建一个线程. 从JAVA1.4开始引入了NIO API, NI ...

  4. Socket通信中AF_INET 和 AF_UNIX域的区别

    转载:http://blog.csdn.net/sandware/article/details/40923491 1.  AF_INET域socket通信过程 典型的TCP/IP四层模型的通信过程. ...

  5. 基于NIO的Socket通信

    一.NIO模式的基本原理: 服务端: 首先,服务端打开一个通道(ServerSocketChannel),并向通道中注册一个通道调度器(Selector):然后向通道调度器注册感兴趣的事件Select ...

  6. AF_INET域与AF_UNIX域socket通信原理对比【转】

    转自:https://www.cnblogs.com/lfxiao/p/9672797.html 1.  AF_INET域socket通信过程 典型的TCP/IP四层模型的通信过程. 发送方.接收方依 ...

  7. Linux 下socket通信终极指南(附TCP、UDP完整代码)

    linux下用socket通信,有TCP.UDP两种协议,网上的很多教程把两个混在了一起,或者只讲其中一种.现在我把自己这两天研究的成果汇总下来,写了一个完整的,适合初学者参考,也方便自己以后查阅. ...

  8. AF_INET域与AF_UNIX域socket通信原理对比

    原文 1.  AF_INET域socket通信过程 典型的TCP/IP四层模型的通信过程. 发送方.接收方依赖IP:Port来标识,即将本地的socket绑定到对应的IP端口上,发送数据时,指定对方的 ...

  9. socket编程之select相关

    FD_ZERO,FD_ISSET这些都是套节字结合操作宏 看看MSDN上的select函数, 这是在select   io   模型中的核心,用来管理套节字IO的,避免出现无辜锁定. int   se ...

随机推荐

  1. C# 关于out关键字的用法(一个方法返回多个值的问题)

    通常一个方法只能返回一个值,但是如果在某些时候,我们想要返回多个值,例如某个方法将一个浮点数分割成一个整数和一个小数返回去.这个时候我们就要用到out关键字. 如果用ref也可以解决,但是用ref需要 ...

  2. CSS学习笔记——盒模型,块级元素和行内元素的区别和特性

    今天本来打算根据自己的计划进行前端自动化的学习的,无奈早上接到一个任务需求需要新增一个页面.自从因为工作需要转前端之后,自己的主要注意力几 乎都放在JavaScript上面了,对CSS和HTML这方面 ...

  3. word 中巧妙添加分隔线

  4. 2014年1月9日 Oracle 实用系统函数

    1.空值处理 1.1 NVL(column/value,VALUE2) 与SQLSERVER的ISNULL相同 1.2 NVL2(column/value,Value2,Value3) 若参数1为空则 ...

  5. 关于ajax提交的公共接口的一大用处

    在项目框架搭建的时候,就写了ajax提交的公共接口,是想统一的日志和处理ajax返回的错误信息. 今天,却又帮我解决了另外一个问题:每次点开某个页面,有一个ajax请求总是会调用两次,于是打开chro ...

  6. inline 间距

    今天看了内联元素的间距: http://blog.csdn.net/hedong37518585/article/details/6657853

  7. SQL Server中in与exist效率比较

    in和exists in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询. 一直以来认为exists比in效率高的说法是不准确的. 如果查询的两 ...

  8. MYSQL SQL Server 事务

    开始: start transaction;   #   一定要有这个 ‘;’ 号. 注意: MYSQL  用的是快照隔离.就是说一个连接在修改的时候别的连接还是可以查询的. 例子: create t ...

  9. Android ListView A~Z快速索引(改进版)

    上一篇文章虽然实现了ListView 快速索引的效果,但是有一个小小的Bug.这个Bug我在前面也说了,这篇文章就来解决这个Bug. 我研究的时候发现只要showBg值为true,中间的字母就显示,而 ...

  10. JIRA官方:JIRA源代码集成

    防火墙后的Git 使用Atlassian Stash创建和管理Git存储库,设置细粒度的权限并在代码上协作.这一切—安全.快速.可靠,更重要的是,可以部署在防火墙后面.JIRA问题关键字自动将JIRA ...