16_网络IPC15-Socket Select 构建高效网络通信模型

使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。在网络编程中,当涉及到多客户访问服务器的情况,我们首先想到的办法就是fork出多个进程来处理每个客户连接,或者使用多线程处理。现在,我们同样可以使用select来处理多客户问题,而不用fork或者多线程,只在单线程既可处理。

以下代码例程照抄自:https://blog.csdn.net/weixin_41010318/article/details/80257177

用于理解

server.c

#include <sys/types.h> 
#include <sys/socket.h> 
#include <stdio.h> 
#include <netinet/in.h> 
#include <sys/time.h> 
#include <sys/ioctl.h> 
#include <unistd.h> 
#include <stdlib.h>
#define LINTEN_QUEUE 5
#define PORT 8888
#define MAXLEN 1024
 
int socket_bind_listen()
{
    struct sockaddr_in server_address;
    int server_sockfd;
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(PORT);
 
    bind(server_sockfd, (struct sockaddr*) & server_address, sizeof(server_address));
    listen(server_sockfd, LINTEN_QUEUE); 
 
    return server_sockfd;
}
void socket_select(int server_sockfd)
{
    fd_set readfds, testfds;
    int client_sockfd;
    struct sockaddr_in client_address;
    int client_len;
    FD_ZERO(&readfds);
    FD_SET(server_sockfd, &readfds);//将服务器端socket加入到集合中
 
    struct timeval tv;
    while (1)
    {
	tv.tv_sec = 5;
	tv.tv_usec = 0;
 
	int fd;
	int nread;
	testfds = readfds;//将需要监视的描述符集copy到select查询队列中,select会对其修改,所以一定要分开使用变量 
 
	int result = select(FD_SETSIZE, &testfds, (fd_set*)0, (fd_set*)0, NULL); //FD_SETSIZE:系统默认的最大文件描述符
	if (result < 0)
	{
    	    perror("server selelct error");
	    exit(1);
	}
	else if (result == 0)
	{
	    printf("time out\n");
	    //continue;
	}
 
	/*扫描所有的文件描述符*/
	for (fd = 0; fd < FD_SETSIZE; fd++)
	{
	    /*找到相关文件描述符*/
	    if (FD_ISSET(fd, &testfds))
	    {
	        /*判断是否为服务器套接字,是则表示为客户请求连接。*/
	        if (fd == server_sockfd)
		{
		    client_len = sizeof(client_address);
		    client_sockfd = accept(server_sockfd, (struct sockaddr*) & client_address, &client_len );
 
		    FD_SET(client_sockfd, &readfds);//将客户端socket加入到集合中
		    printf("adding client on fd %d\n", client_sockfd);
		}
		/*客户端socket中有数据请求时*/
		else
		{
		    ioctl(fd, FIONREAD, &nread);//取得数据量交给nread
 
		    /*客户数据请求完毕,关闭套接字,从集合中清除相应描述符 */
	            if (nread == 0)
	     	    {
	                close(fd);
			FD_CLR(fd, &readfds); //去掉关闭的fd
			printf("removing client on fd %d\n", fd);
		    }
		    /*处理客户数据请求*/
		    else
		    {
			char buf[MAXLEN] = "";
			recv(fd, buf, MAXLEN, 0);
			printf("buf:%s\n", buf);
			printf("serving client on fd %d\n", fd);
		    }
		}
	    }
	}
    }
}
int main() 
{ 
    int server_sockfd; 
    
    server_sockfd = socket_bind_listen();
 
    socket_select(server_sockfd);
    
    return 0;
}

client.c

#include <sys/types.h> 
#include <sys/socket.h> 
#include <stdio.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
int main() 
{ 
    int client_sockfd; 
    int len; 
    struct sockaddr_in address;//服务器端网络地址结构体 
    int result; 
 
    client_sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立客户端socket 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = htons(8888); 
 
    len = sizeof(address); 
    result = connect(client_sockfd, (struct sockaddr *)&address, len); 
 
    if(result == -1) 
    { 
         perror("oops: client2"); 
         exit(1); 
    } 
    char buf[1024] = "hello";
    send(client_sockfd, buf, strlen(buf), 0);
    close(client_sockfd); 
 
    return 0; 
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值