精选 select 模型:实现服务器端和客户端代码 (select模型服务器端和客户端代码)

精选 SELECT 模型:实现服务器端和客户端代码

作为现代计算机应用开发中最广泛使用的两个平台,服务器和客户端是解决客户和服务交互的重要基础。而实现这两个平台的代码,则必须是高度灵活和功能强大的,以满足不同应用的需要。为此,开发人员需要使用一种可靠,可拓展并且强大的模型。

SELECT模型是一种高效的模型,它是开发人员用于创建高度可扩展,可伸缩和底层 I/O 传输的关键工具。通过数据流聚合输入为套接字的事件,SELECT模型允许开发人员以非阻止或异步方式获取数据,并向客户端提供可用。

在本文中,我们将深入研究SELECT模型的原理,并演示如何使用它来构建服务器和客户端代码。

SELECT模型的原理

SELECT模型是Linux和Windows操作系统中很常见的系统调用。该模型通过一种集中的单线程事件循环机制来管理多个套接字连接。当SELECT模型开始监听套接字时,它会等待客户端发送数据,而不会阻塞服务列表中的事件。

选择模型涉及使用select系统调用来侦听I/O事件,如读取和写入。从而使一个I/O流被处理,而不需要使线程一直阻塞在该操作上,同时它还可进行轮询等操作。

SELECT模型是管理现代计算机应用程序中多个连接的一种有效方式。换句话说,它使一个进程能够同时监听多个套接字,实现跨网络连接的数据传输。

如下所示,SELECT模型的主要组件:

1. 文件描述符列表:用于存储套接字描述符。

2. 输入类型:用于存储套接字的输入类型(读取,写入,错误)。

3. 时间值:指示SELECT模型应该等待事件的时间戳,以避免频繁检查描述符表。

SELECT模型有优秀的伸缩性,因为其设计支持处理许多并发的网络连接。 它的工作原理如下:

SELECT模型将套接字添加到描述符列表中。然后,它轮流等待事件,并选择发生I/O事件的描述符。一旦有一个连接事件发生,接收数据的套接字就准备好处理数据。然后,开发人员可以执行必要的操作来处理数据。SELECT模型更新时间值并检查下一个事件。

使用SELECT模型构建服务器端代码

在这个案例中,我们将使用SELECT模型来开发一个简单的Web服务器。 我们声明必要的库:

“`

#include

#include

#include

#include

#include

#include

#include

#include

“`

声明主要变量

创建描述符表fd_set来保存所有Socket,并建立一个监听套接字serverfd:

“`

fd_set master_fds, fds;

int max_sockfd, clientfd [1024], max_client = -1, sockfd, len;

char buffer[1025];

struct sockaddr_in serveraddr, clientaddr;

“`

初始化描述符表fd_set

使用FD_ZERO初始化描述符表fd_set,并将serverfd添加到主描述符表中:

“`

FD_ZERO(&master_fds);

FD_SET(serverfd, &master_fds);

“`

监听套接字serverfd

使用listen函数将serverfd绑定在给定的IP地址和端口号上。

“`

serverfd = socket(AF_INET, SOCK_STREAM, 0);

memset(&serveraddr, 0, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_port = htons(PORT);

serveraddr.sin_addr.s_addr = htons(INADDR_ANY);

bind(serverfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

listen(serverfd, 5);

“`

使用fd_set描述符来接受传入套接字连接

使用FD_ISSET函数检查用于接收连接的描述符和主描述符。然后,使用accept函数接受连接,将连接套接字添加到connfd中。在客户端连接列表中存储该客户端套接字。

“`

while (true) {

fds = master_fds;

if (select(max_sockfd + 1, &fds, NULL, NULL, NULL) == -1) {

perror(“select”);

exit(EXIT_FLURE);

}

for (sockfd = 0; sockfd

if (FD_ISSET(sockfd, &fds)) {

if (sockfd == serverfd) {

len = sizeof(clientaddr);

clientfd[max_client + 1] = accept(serverfd, (struct sockaddr *)&clientaddr, &len);

if(clientfd[max_client + 1] == -1) {

perror(“accept”);

} else {

FD_SET(clientfd[max_client + 1], &master_fds);

if (clientfd[max_client + 1] > max_sockfd) {

max_sockfd = clientfd[max_client + 1];

}

if (max_client

max_client = max_sockfd;

}

printf(“Accept connection from %s on port %d\n”, inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

}

} else {

if ((len = recv(sockfd, buffer, sizeof(buffer), 0))

if (len == 0) {

printf(“Connection closed with Client with server FD: %d\n”, sockfd);

} else {

perror(“recv”);

}

close(sockfd);

FD_CLR(sockfd, &master_fds);

if (sockfd == max_sockfd) {

while (FD_ISSET(max_sockfd, &master_fds) == false) {

max_sockfd -= 1;

}

}

} else {

buffer[len] = ‘\0’;

printf(“Received data from Client with Server FD: %s\n”, buffer);

}

}

}

}

}

“`

使用SELECT模型构建客户端代码

在这个案例中,我们将使用SELECT模型来开发一个简单的客户端,它连接到同一SERVER FD并发送字符串。

声明必要的库:

“`

#include

#include

#include

#include

#include

#include

#include

#include

#include

“`

声明变量

然后,声明需要的变量,包括套接字描述符clientfd和描述符列表fds:

“`

int sockfd, len;

struct sockaddr_in serveraddr;

char buffer[1025];

fd_set fds;

“`

建立套接字

通过socket函数建立TCP套接字。

“`

clientfd = socket(AF_INET, SOCK_STREAM, 0);

memset(&serveraddr, 0, sizeof(serveraddr));

“`

设置服务器地址

使用inet_pton函数将IP地址转换为网络字节序,并将其存储在服务器地址结构体中。

“`

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.s_addr = inet_addr(ipaddr); //IP地址

serveraddr.sin_port = htons(portno); //端口号

“`

与服务器建立连接

使用connect函数与服务器建立连接。

“`

if (connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))

perror(“Connect()”);

exit(EXIT_FLURE);

}

“`

发送消息

使用FD_ZERO,FD_SET和FD_ISSET等函数,通过SELECT模型检查描述符列表。在建立连接后,使用write函数将要发送的消息存储在buffer中,并将其发送给服务器。

“`

while(strncmp(buffer, “END”, strlen(buffer)-1) != 0) {

FD_ZERO(&fds);

FD_SET(clientfd, &fds);

FD_SET(STDIN_FILENO, &fds);

select(clientfd + 1, &fds, NULL, NULL, NULL);

if (FD_ISSET(STDIN_FILENO, &fds)) {

fgets(buffer, sizeof(buffer), stdin);

len = strlen(buffer);

if (write(clientfd, buffer, len) != len ) {

perror(“Write() error\n”);

exit(EXIT_FLURE);

}

}

}

“`

关闭连接

使用close函数关闭客户端套接字。

“`

printf(“Exiting client.\n”);

close(clientfd);

return 0;

“`

结论


数据运维技术 » 精选 select 模型:实现服务器端和客户端代码 (select模型服务器端和客户端代码)