ZBLOG

基于udp非阻塞io实现高并发的demo C

下面是一个基于UDP非阻塞IO的高并发Demo的C代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAX_BUFFER_SIZE 1024
#define MAX_CLIENTS 1000

int main() {
    int serverSocket, clientSockets[MAX_CLIENTS];
    struct sockaddr_in serverAddr, clientAddr;
    char buffer[MAX_BUFFER_SIZE];
    socklen_t addrLen = sizeof(clientAddr);

    // 创建服务器socket
    if ((serverSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Failed to create socket");
        exit(1);
    }

    // 设置服务器socket为非阻塞模式
    int flags = fcntl(serverSocket, F_GETFL, 0);
    fcntl(serverSocket, F_SETFL, flags | O_NONBLOCK);

    memset(&serverAddr, 0, sizeof(serverAddr));
    
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(12345); // 设置端口号
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定服务器地址和端口号
	if (bind(serverSocket, (struct sockaddr *)&serverAddr , sizeof(serverAddr)) == -1) {
		perror("Failed to bind");
		exit(1);
	}

	printf("Server started. Listening for incoming connections...\n");

	fd_set readfds; // 可读文件描述符集合
	int maxSockFd = serverSocket + 1; // 最大文件描述符值+1

	while (1) {
		FD_ZERO(&readfds); // 清空可读文件描述符集合
		FD_SET(serverSocket, &readfds); // 将服务器socket加入到可读文件描述符集合

		// 检测所有客户端socket,并将其加入到可读文件描述符集合中
		for (int i = 0; i < MAX_CLIENTS; i++) {
			if (clientSockets[i] > 0) {
				FD_SET(clientSockets[i], &readfds);
				if (clientSockets[i] >= maxSockFd) {
					maxSockFd = clientSockets[i] + 1;
				}
			}
		}

        // 使用select函数进行IO多路复用,监听可读事件
		if (select(maxSockFd, &readfds, NULL, NULL, NULL) == -1) {
			perror("Failed to select");
			exit(1);
		}

        // 如果服务器socket有可读事件,则处理新的连接请求
        if (FD_ISSET(serverSocket, &readfds)) {
            int newClientSocket;
            
            // 接受新的客户端连接
            if ((newClientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &addrLen)) == -1) {
                perror("Failed to accept");
                exit(1);
            }

            printf("New connection established. Client socket: %d\n", newClientSocket);

            // 将新的客户端socket设置为非阻塞模式,并添加到客户端socket数组中
            flags = fcntl(newClientSocket, F_GETFL, 0);
	        fcntl(newClientSocket, F_SETFL, flags | O_NONBLOCK);

	        for (int i = 0; i < MAX_CLIENTS; i++) {
                if (clientSockets[i] == 0) {
                    clientSockets[i] = newClientSocket;
                    break;
                }
            }
        }

        // 遍历所有客户端socket,检查是否有数据可读
		for (int i = 0; i < MAX_CLIENTS; i++) {
			if (clientSockets[i] > 0 && FD_ISSET(clientSockets[i], &readfds)) {
				memset(buffer, '\0', sizeof(buffer));
                
                // 接收客户端发送的数据
                ssize_t bytesRead = recvfrom(clientSockets[i], buffer, sizeof(buffer), 0, (struct sockaddr *)&clientAddr, &addrLen);

                if (bytesRead > 0) {
                    printf("Received data from client %d: %s\n", clientSockets[i], buffer);
                    
                    // 这里可以添加业务逻辑处理
                    
                    // 将数据回传给客户端
					sendto(clientSockets[i], buffer, strlen(buffer), 0, (struct sockaddr *)&clientAddr, addrLen);
				}
                else if (bytesRead == 0) { // 客户端关闭连接
					printf("Client %d disconnected.\n", clientSockets[i]);
					close(clientSockets[i]);
					clientSockets[i] = 0;
				}
                else if (errno != EWOULDBLOCK && errno != EAGAIN) { // 发生错误
					perror("Failed to receive");
					close(clientSockets[i]);
					clientSockets[i] = 0;
				}
			}
		}
	}

    close(serverSocket);

	return 0;
}

这个示例代码使用UDP协议实现了一个基于非阻塞IO的高并发服务器。它使用select函数进行IO多路复用,可以同时处理多个客户端连接。你可以根据自己的需求进行适当的修改和扩展,添加业务逻辑处理部分。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=2431

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?