select多路复用实现多客户端连接服务器

.>应用程序中同时需要处理多路输入输出流时,若采用阻塞模式,将得不到预期的目的;
.>若采用非阻塞模式,对多个输入进行轮训有太耗费时间;
.>若设置多个进程分别处理一天数据通路,将产生新的进程同步通信问题,使程序更复杂;
比较好的方法就是采用多路复用,其基本思想就是:
》》》先创建一张有关描述符的的表,然后调用一个函数,当这些文件描述符中的一个或者多个已经准备好进行IO操作时函数才返回;
》》》函数返回时告诉进程哪个描述符已就绪,可以进行IO操作;
函数原型:
    int select(int nfds,fd_set *readset,fd_set *writeset,fd_set* exceptset,struct timeval *timeout);
nfds:     第一个参数是:最大的文件描述符值+1;
readset:    可读描述符集合;
writeset:   可写描述符集合;
exceptset:   异常描述符;
timeout:select 的监听时长,如果这短时间内所监听的 socket 没有事件发生。
设置文件描述符的几个宏:
FD_ZERO(fd_set *)        从fd_set中清除所有文件描述符;
FD_SET(int fd, fd_set *)    将fd添加到fd_set中; 
FD_CLR(int fd, fd_set *)    将fd从fd_set中清除;
FD_ISSET(int fd, fd_set *)   判断fd是否在fd_set中;
通俗点解释,就是将需要监听的文件描述符添加到fd_set这个文件描述符集合中,然后用宏函数FD_ISSET()判断该文件描述符是否存在,因为进行循环后只有有需要处理的文件描述符才会留在这个文件描述符集合中,否则就会被清除,在对相应描述符进行操作;

//tcp 多路复用服务器端
#include "tcp.h"
int main()
{
int socketID  = 0;
int maxFd = 0;
int ret = 0;
int newID = 0;
fd_set readFds;
int addrLength = 0;
struct sockaddr_in addr;
char buf[SIZE] = {0};
//init socket
socketID = initSocket();
if (0 > socketID)
{
printf("socket init error\r\n");
return ERROR;
}
printf("init socket success\r\n");
addrLength = sizeof(addr);
//多路复用
maxFd = socketID;
FD_ZERO(&readFds);
FD_SET(socketID, &readFds);
while(1)
{
//设定:把所有要监听的描述符都放到监听集合中
fd_set tmp = readFds;
    ret = select(maxFd + 1, &tmp, NULL, NULL, NULL);
    if (0 > ret)
    {
    perror("select error");
    return ERROR;
    }
    else if (0 == ret)
    {
    printf("select time out\r\n");
    }
    else 
    {
    //判断哪一个描述符可读
int i = 0;
for (i = 0; i <= maxFd; i++)
{
if (FD_ISSET(i, &tmp))
{
if (i == socketID)
{
memset(&addr, 0, addrLength);
newID = accept(socketID, (struct sockaddr *)&addr, &addrLength);
if (0 > newID)
{
perror("accept error");
return ERROR;
}
printf("client %d connected, IP=%s,port=%u\r\n", newID, (char *)inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
//把newID加入到监听描述符集合中
FD_SET(newID, &readFds);
if (newID > maxFd)
{
maxFd = newID;
}
continue;
}//if (i == socketID)
//判断newID是否可读
memset(buf, 0, SIZE);
ret = recv(i, buf, SIZE - 1, 0);
if (0 > ret)
{
perror("recv error");
close(i);
FD_CLR(i, &readFds);
printf("client %d closed\r\n", i);
}
else if (0 == ret)
{
close(i);
FD_CLR(i, &readFds);
printf("client %d closed\r\n", i);
}
else 
printf("client %d said:%s\r\n", i, buf);
}//if (FD_ISSET(i, &tmp))
}//for(i = 0; i <= maxFd; i++)
    }//else
}//while(1)
close(socketID);
return 0;
}
int initSocket()
{
int socketID  = 0;
int addrLength = 0;
int flag = 1;
struct sockaddr_in addr;
//创建socket
socketID = socket(AF_INET, SOCK_STREAM, 0);
if (socketID < 0)
{
perror("socket error");
return ERROR;
}
//设置地址可以重复绑定
if( setsockopt(socketID, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)  
    {  
        perror("setsockopt");  
        return ERROR;  
    } 
//bind
addrLength = sizeof (addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (0 > bind(socketID, (struct sockaddr *)&addr, addrLength))
{
perror("bind error");
return ERROR;
}
//listen
if (0 > listen(socketID, LISTENNUM))
{
perror("listen error");
return ERROR;
}
return socketID;
} 

/*tcp  通信, 客户端*/
#include "tcp.h"
int main()
{
//定义变量
int socketID = 0;
int addrLength = 0;
int ret = 0;
struct sockaddr_in addr;
char buf[SIZE] = {0};
//创建套接字
socketID = socket(AF_INET, SOCK_STREAM, 0);
if (socketID < 0)
{
perror("socket error");
return -1;
}
//设定对方的IP/PORT
addrLength = sizeof(addr);
memset(&addr, 0, addrLength);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IP);
//发送连接请求 
ret = connect(socketID, (const struct sockaddr *)(&addr), addrLength);
if (ret < 0)
{
perror("connect error");
close(socketID);
return -1;
}
printf("connect success\r\n");
//通信(发,收)
while(1)
{
fgets(buf, SIZE - 1, stdin);
ret = send(socketID, buf, strlen(buf), 0);
if (ret < 0)
{
perror("send error");
close(socketID);
return -1;
}
printf("send success %s,%d\r\n", buf, ret);
if (strncmp(buf, "quit", 4) == 0)
{
break;
}
}
//关闭套接字
close(socketID);
return 0;
}
程序可实现多客户端与服务器端进行连接,而服务器都可及时响应客户端,不会出现服务器
阻塞;
时间: 2024-08-09 10:44:27

select多路复用实现多客户端连接服务器的相关文章

基于TCP网络通信的自动升级程序源码分析-客户端连接服务器

服务器开始监听 //从配置文件获取要监听的IP和端口 string strIP = System.Configuration.ConfigurationManager.AppSettings["IPAddress"]; int port = int.Parse(System.Configuration.ConfigurationManager.AppSettings["Port"]); //开始监听 Connection.StartListening(Connect

Android学习笔记一之客户端连接服务器

1.客户端连接服务器实例剖析: 第一步:在浏览器,客户端输入得到用户输入的内容. 第二步:浏览器得到这个网址之后,内部会将这个域名发送到DNS上进行域名解析.解析得到这个网址的IP地址之后,客户端会链接到指定的服务器上. 第三步:实现TCP/IP协议用Socket完成,使用了Socket的套接字. 第四步:服务器端的端口监听客户端的连接,这样客户端就和服务器连接上了. 2.当服务器监听到了客户端的请求之后,服务器会以三种方式返回给客户端,最常用的是以HTML,也就是网页的形式返回,还可以以XML

《SSH客户端连接服务器(SecureCRT)》

(1)SSH那些事儿 ①openssh:是提供SSH服务的程序: openssl:是为SSH提供连接加密的程序. ②网络服务一般会有一个端口,端口是一个数字.(0-65535)     SSH端口为22. ③SSH客户端 :windows平台有:SecureCRT.xshell.putty SSH协议是:Secure Shell Protocol的的简写. ④SSH是专门为远程登录会话和其他网络服务提供的安全性协议. ⑤SSH两个不兼容的版本:SSHv1.SSHv2. ⑥查看SSH服务:a.ne

Oracle 客户端连接服务器[转]

很多朋友在开发项目中并不是每个人用一个数据库,而是有单独的一台主机作为开发的数据库服务器,这样,就需要我们的开发人员去连接它.          首先是进入oracle的 Net  Mananger: 接下来就是进行简单的设置了..          (1)点击服务命名,再点击此处的“+”号 : 进入到如下界面,当中的服务名可以自己定义,我这里的是 “service”.代表连接数据库服务器,而非本机: 点下一步,选择tcp/ip协议   再进入到下一步,将要监听的目标主机的IP地址输入进去,  

Telnet客户端连接服务器,看不见字符,只显示横线

Telnet 窗口看不见字符,只显示小横线 在用telnet连接tomcat服务器的 时候,窗口中不显示字符,显示成一个一个的横线 解决办法: 按住“Ctrl+]” 回车解决问题

一、SecureCRT 8.0 客户端连接服务器

1.通过远程连接服务器linux,连接的是ssh服务: 如图:ssh2协议是ssh的升级版. 连接模式: 2. Ctrl+d 快速退出==exit/quit/logout 3.SecureCRT 改变客户端字体.背景颜色.鼠标颜色.日志存放位置.上传下载,都在这个模块下 4.客户端和服务器端的上传下载命令: 下载:sz -y    (本地有,-y进行覆盖) 上传:rz  -y (服务器有,-y进行覆盖) 两个命令在 Dial-up Networking  Support包里面 下载这个包有两种命

修改客户端连接的服务器IP地址

Windows XP 步骤如下:1 点击 开始2 点击 运行3 输入 regedit4 点击 确定5 点击 HKEY_CURRENT_USER 左边加号+6 点击 Software 左边加号 +7 点击 zdedumanager8 右键点击 AppServer IP:9 点击 修改10 输入新的IP,比如 202.200.112.20211 点击  确定12 关闭窗口,完成Windows 7 步骤如下:1 点击 开始2 鼠标点到"关机"左边的文本框3 输入 regedit4 按回车键5

用友U8客户端连接不上服务器全攻略

用友U8客户端连接不上服务器全攻略 http://www.enet.com.cn2009年09月23日09:26 来自论坛 [导读]:如果网络不通,就让用户查找网络原因 检查步骤: 1.网络是否通? 方法:ping 服务器名称/ip -t 如果网络不通,就让用户查找网络原因: 如果网络是通的,继续…… 2.尝试使用ip地址登录服务器 如果无效,继续…… 3.配置hosts文件,将服务器+ip加入(路径:C:\WINNT\system32\drivers\etc\hosts) 如果配置hosts文

微风IM 3.3 系列之二 服务器开始监听与客户端连接

通信框架为networkcomms2.3.1 服务器端监听代码: //从配置文件获取IP和端口 string strIP = System.Configuration.ConfigurationManager.AppSettings["IPAddress"]; int port = int.Parse(System.Configuration.ConfigurationManager.AppSettings["Port"]); IPEndPoint thePoint