用c语言 写一个非阻塞的tcp 服务器
时间: 2023-11-21 15:04:10 浏览: 45
非阻塞的TCP服务器可以使用select函数来实现。以下是一个示例代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
int server_fd, client_fds[MAX_CLIENTS], max_fd, activity, i, j, valread;
struct sockaddr_in address;
char buffer[BUFFER_SIZE] = {0};
fd_set read_fds;
// 创建服务器socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(1);
}
// 设置socket为非阻塞模式
if (fcntl(server_fd, F_SETFL, O_NONBLOCK) < 0) {
perror("fcntl failed");
exit(1);
}
// 设置服务器socket地址
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(atoi(argv[1]));
// 绑定服务器socket和地址
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(1);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen failed");
exit(1);
}
// 初始化客户端socket数组
for (i = 0; i < MAX_CLIENTS; i++) {
client_fds[i] = 0;
}
// 主循环
while (1) {
// 清空fd_set
FD_ZERO(&read_fds);
// 添加服务器socket到fd_set
FD_SET(server_fd, &read_fds);
max_fd = server_fd;
// 添加客户端socket到fd_set
for (i = 0; i < MAX_CLIENTS; i++) {
int client_fd = client_fds[i];
if (client_fd > 0) {
FD_SET(client_fd, &read_fds);
if (client_fd > max_fd) {
max_fd = client_fd;
}
}
}
// 监听所有socket
activity = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
if (activity < 0) {
perror("select failed");
exit(1);
}
// 处理服务器socket连接请求
if (FD_ISSET(server_fd, &read_fds)) {
int new_socket;
struct sockaddr_in client_address;
socklen_t client_address_len = sizeof(client_address);
if ((new_socket = accept(server_fd, (struct sockaddr *)&client_address, &client_address_len)) < 0) {
perror("accept failed");
exit(1);
}
// 设置新连接的socket为非阻塞模式
if (fcntl(new_socket, F_SETFL, O_NONBLOCK) < 0) {
perror("fcntl failed");
exit(1);
}
// 将新连接的socket添加到客户端socket数组
for (i = 0; i < MAX_CLIENTS; i++) {
if (client_fds[i] == 0) {
client_fds[i] = new_socket;
break;
}
}
}
// 处理客户端socket数据
for (i = 0; i < MAX_CLIENTS; i++) {
int client_fd = client_fds[i];
if (FD_ISSET(client_fd, &read_fds)) {
if ((valread = read(client_fd, buffer, BUFFER_SIZE)) == 0) {
// 客户端关闭连接
close(client_fd);
client_fds[i] = 0;
} else {
// 处理客户端数据
buffer[valread] = '\0';
printf("Received: %s", buffer);
}
}
}
}
return 0;
}
```
在此示例中,使用了select函数来监听所有socket的读事件,并将服务器socket和客户端socket分别添加到fd_set中。当有新的客户端连接请求时,accept函数会返回一个新的socket,将该socket设置为非阻塞模式后,将其添加到客户端socket数组中。当有客户端socket有数据可读时,read函数会返回读取到的字节数,如果返回0则表示客户端关闭连接,此时需要将该socket从客户端socket数组中移除。否则,可以处理读取到的数据。