Linux 基于UDP的服务器无法区分不同的用户 这是一个基于UDP协议与所有客户端通信的C++服务器应用程序。当用户从客户端登录到服务器时,客户端应用程序向服务器注册一个UDP通道,该通道采用固定格式:IP+端口,这意味着如果IP保持不变,则无论登录到客户端的用户注册同一通道
服务器的套接字层维护一个心跳机制,如果在3分钟内没有从通道接收到任何心跳数据包,该机制将删除通道。在客户端关闭之前,一切正常,例如,网络线已断开。请看下面的场景:Linux 基于UDP的服务器无法区分不同的用户 这是一个基于UDP协议与所有客户端通信的C++服务器应用程序。当用户从客户端登录到服务器时,客户端应用程序向服务器注册一个UDP通道,该通道采用固定格式:IP+端口,这意味着如果IP保持不变,则无论登录到客户端的用户注册同一通道,linux,networking,udp,client-server,heartbeat,Linux,Networking,Udp,Client Server,Heartbeat,服务器的套接字层维护一个心跳机制,如果在3分钟内没有从通道接收到任何心跳数据包,该机制将删除通道。在客户端关闭之前,一切正常,例如,网络线已断开。请看下面的场景: 1. User-A logs into server. The Client registers channel (IP:Port) to the server. Because the UDP channel is alive, so the Server sets the User stat
1. User-A logs into server. The Client registers channel (IP:Port)
to the server. Because the UDP channel is alive, so the Server
sets the User status of User-A as Online.
2. Kill the client process, and within 3 minutes(before the channel
timeouts in server), let User-B logs into server from the same
computer. Because the IP remains unchanged, so actually the client
registers a same (IP:PORT) pair to the server as it did when User-A
logs in.
3. Since the Server receives packets from (IP:PORT), so it considers
User-A is still alive, thus setting the user status of User-A as
Online which is not right anymore.
在上述场景中,服务器无法区分从同一台计算机登录的不同用户,这将导致错误的用户状态。有人知道如何解决这个问题吗 除非客户端应用程序显式绑定UDP套接字,否则没有理由假定任何两个用户的源端口号相同。发起通信的客户端通常可以同样有效地使用临时端口。对于您的特定用例,临时端口可能是随机的,也可能不是随机的,下面的代码显示了如何从入站UDP数据访问客户端端口。如果它们不够随机,则最好将会话cookie或用户cookie编码到协议中
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
int
main() {
/*- setup UDP socket on 8500 */
int rc;
int server_socket;
struct sockaddr_in server_address;
server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket < 0) {
perror("failed to init socket");
return 1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8500);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
rc = bind(server_socket, (struct sockaddr*) &server_address
, sizeof(server_address));
if (rc < 0) {
perror("failed to bind");
return 2;
}
/* - receive from UDP socket and print out origin port - */
char buffer[4096];
struct sockaddr_in client_address;
int client_address_len = sizeof(client_address);
rc = recvfrom(server_socket
, buffer
, sizeof(buffer)
, 0
, (struct sockaddr*) &client_address
, &client_address_len);
if (rc < 0)
return 3;
fprintf(stderr, "%s %d\n", buffer, ntohs(client_address.sin_port));
return 0;
}
您可以实现某种身份验证。将通道的签名从IP:PORT扩展到IP:PORT:USER