mysql的tcp可以多路复用吗_select多路复用实现多客户端连接服务器

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 

#include 

#include 

#include 

#include 

#define SIZE 32

#define IP   "127.0.0.1"

#define PORT 54321

#define LISTENNUM 5

enum SOCK_OP

{

ERROR = -1,

SUCCESS = 0,

};

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 

{

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 

#include 

#include 

#include 

#include 

#define SIZE 32

#define IP   "127.0.0.1"

#define PORT 54321

#define LISTENNUM 5

enum SOCK_OP

{

ERROR = -1,

SUCCESS = 0,

};

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 

{

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 

{

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 

{

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;

}

程序可实现多客户端与服务器端进行连接,而服务器都可及时响应客户端,不会出现服务器

阻塞;

©著作权归作者所有:来自51CTO博客作者主宰之路的原创作品,如需转载,请注明出处,否则将追究法律责任

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值