为游戏服务器处理多个客户端
Handling multiple clients for game server
我无法弄清楚如何在不阻塞服务器的情况下存储客户端句柄。我遵循 Stevens 在 "The Socket Networking API" 中详述的并发服务器模型。
我的程序创建玩家之间的井字游戏比赛。
程序的结构是这样的:服务器处理两个 TCP/UDP 连接。客户端程序可以查询或连接到服务器。如果客户端查询,UDP 套接字通过 returning 已连接客户端的句柄列表来处理查询。
如果客户端连接,TCP 套接字通过以下方式处理连接:1. 向客户端请求句柄和 2. 存储他们的句柄。如果有两个连接的客户端,则会产生一个单独的进程来在它们之间创建匹配(但这现在不相关)。
在我的程序中,我将 TCP/UDP 套接字与 select()
复用。我当前的问题是如何在不阻塞的情况下处理询问和存储客户端句柄。
我考虑过:
- 正在创建另一个线程来处理请求和接收客户端句柄。
保留已连接客户端套接字的列表,并将它们添加到 fd_set 数据结构,并在它们之间多路复用 TCP/UDP 套接字。
生成另一个进程来处理 asking/receiving 句柄,但这是不可能的,因为我将句柄存储在全局链表数据结构中,以便服务器可以 return 查询时的列表。与 parent 沟通太麻烦了。
*下面的代码还没有经过测试并且不完整,因为我还没有想出如何解决这个问题。
game_head = NULL; game_tail = game_head;
/* Creating TCP listening socket */
tcp_listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(TCP_PORT);
bind(tcp_listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(tcp_listenfd, LISTENQ);
/* Creating UDP socket */
udpfd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(UDP_PORT);
bind(udpfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
/* Signal handling (also possibly handle SIGCHLD)*/
signal(SIGINT, sighandler);
signal(SIGUSR2, sighandler);
FD_ZERO(&rset);
maxfdp1 = max(tcp_listenfd, udpfd) + 1;
while(1) {
if (terminate)
terminate_program();
FD_SET(tcp_listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else
perror("select error");
}
if (FD_ISSET(tcp_listenfd, &rset)) {
len = sizeof(cliaddr);
tcp_connfd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len);
close(tcp_connfd);
}
if (FD_ISSET(udpfd, &rset)) {
}
}
不要关闭 tcp_listenfd
。使用一组 TCP 连接器,即 tcp_connfd[10]
或其他东西,然后计算您拥有的 TCP 数量。为每个客户分配一个新号码。
祝你好运!
我无法弄清楚如何在不阻塞服务器的情况下存储客户端句柄。我遵循 Stevens 在 "The Socket Networking API" 中详述的并发服务器模型。
我的程序创建玩家之间的井字游戏比赛。
程序的结构是这样的:服务器处理两个 TCP/UDP 连接。客户端程序可以查询或连接到服务器。如果客户端查询,UDP 套接字通过 returning 已连接客户端的句柄列表来处理查询。
如果客户端连接,TCP 套接字通过以下方式处理连接:1. 向客户端请求句柄和 2. 存储他们的句柄。如果有两个连接的客户端,则会产生一个单独的进程来在它们之间创建匹配(但这现在不相关)。
在我的程序中,我将 TCP/UDP 套接字与 select()
复用。我当前的问题是如何在不阻塞的情况下处理询问和存储客户端句柄。
我考虑过:
- 正在创建另一个线程来处理请求和接收客户端句柄。
保留已连接客户端套接字的列表,并将它们添加到 fd_set 数据结构,并在它们之间多路复用 TCP/UDP 套接字。
生成另一个进程来处理 asking/receiving 句柄,但这是不可能的,因为我将句柄存储在全局链表数据结构中,以便服务器可以 return 查询时的列表。与 parent 沟通太麻烦了。
*下面的代码还没有经过测试并且不完整,因为我还没有想出如何解决这个问题。
game_head = NULL; game_tail = game_head;
/* Creating TCP listening socket */
tcp_listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(TCP_PORT);
bind(tcp_listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(tcp_listenfd, LISTENQ);
/* Creating UDP socket */
udpfd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(UDP_PORT);
bind(udpfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
/* Signal handling (also possibly handle SIGCHLD)*/
signal(SIGINT, sighandler);
signal(SIGUSR2, sighandler);
FD_ZERO(&rset);
maxfdp1 = max(tcp_listenfd, udpfd) + 1;
while(1) {
if (terminate)
terminate_program();
FD_SET(tcp_listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else
perror("select error");
}
if (FD_ISSET(tcp_listenfd, &rset)) {
len = sizeof(cliaddr);
tcp_connfd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len);
close(tcp_connfd);
}
if (FD_ISSET(udpfd, &rset)) {
}
}
不要关闭 tcp_listenfd
。使用一组 TCP 连接器,即 tcp_connfd[10]
或其他东西,然后计算您拥有的 TCP 数量。为每个客户分配一个新号码。
祝你好运!