C中的两种方式UDP套接字
Posted
技术标签:
【中文标题】C中的两种方式UDP套接字【英文标题】:Two way UDP sockets in C 【发布时间】:2012-05-15 06:50:57 【问题描述】:这是关于 UDP 套接字的一个非常基本的问题。我自己已经使用它们编写了一些服务器/客户端应用程序,但我现在卡住了,无法看到问题出在哪里。
我正在尝试做一个可以发送和接收数据报的服务器和客户端。因此,服务器在确定的套接字上等待来自客户端的请求,当它通过它接收到某些内容时,它会将其答案发送给客户端。只要服务器收到请求并发送回答案,它就可以工作,但客户端永远不会得到它。
我在这里展示了一些剥离的代码,只是连接的基本部分:
服务器:
if ((socket_id = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return;
bzero(&server_socket, sizeof(server_socket));
server_socket.sin_family = AF_INET;
server_socket.sin_addr.s_addr = INADDR_ANY;
server_socket.sin_port = htons(8724);
if (bind(socket_id, (struct sockaddr *) &server_socket, sizeof(server_socket)) == -1)
return;
bzero(dgram_buffer, 1024);
client_socket_sz = sizeof(client_socket);
if((dgram_length = recvfrom(socket_id, dgram_buffer, 1024, 0, (struct sockaddr *) &client_socket, (socklen_t *) &client_socket_sz)) == -1)
return;
if (sendto(socket_id, msg_buffer, offset, 0, (struct sockaddr *) &client_socket, (socklen_t) client_socket_sz) < 0)
return;
printf("%s\n", msg_buffer);
客户:
if ((socket_id = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
return;
if ((hostp = gethostbyname(hostname)) == 0)
return;
bzero((char *) &client_socket, sizeof(client_socket));
client_socket.sin_family = AF_INET;
client_socket.sin_port = htons(8724);
bcopy(hostp->h_addr, (char *) &client_socket.sin_addr, hostp->h_length);
bzero(msg_buffer,sizeof(msg_buffer));
memcpy(msg_buffer,"mensaje\0",sizeof("message"));
socklen_t client_socket_len = sizeof(struct sockaddr_in);
if (sendto(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, client_socket_len) < 0)
return;
bzero(msg_buffer,sizeof(msg_buffer));
if(recvfrom(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, &client_socket_len) == -1)
return;
printf("%s\n", msg_buffer);
(我知道缓冲区及其内容没有得到很好的处理;我在我的实际应用程序中做得正确,我只是输入它来快速测试)
谁能给我看看,如果某些设置是错误的,请告诉我?我在网上看过数百个例子,审查了我的旧代码......无济于事。也许我已经在这方面工作了太多小时,而我只是跳过了显而易见的事情。
提前致谢。
【问题讨论】:
你能给我们一些可以编译的东西吗? 顺便说一句,它是否适用于主机名 == "localhost" - 即。客户端和服务器在同一台机器上?我刚刚编译了它,它可以在 OS X 上运行 我尝试切换执行服务器(远程)和客户端(本地)的机器,然后服务器(现在是本地)没有收到任何消息。所以我在两台不同的远程机器上都执行了(虽然在同一个网络上),至少我在这里发布的这个简单代码执行得很好。这是否意味着这是我本地机器的问题? 可能是防火墙问题。您如何连接到互联网? @WilliamMorris 在这里您可以找到服务器:(pastebin.com/7D9ty5Hv) 和客户端:(pastebin.com/UxnVTzun) 【参考方案1】:您需要绑定两个套接字。
您已经将服务器绑定到一个众所周知的端口。 您还应该将客户端绑定到端口 0。这意味着操作系统为此会话选择任意端口。绑定套接字后,您将获得数据包到该端口。
【讨论】:
感谢您的快速回复:)我已经尝试过了,但客户端还是没有得到回复。 尝试窥探流量(tcpdump/wireshark)并查看发送的内容。使用netstat
查看哪个进程监听哪个端口。
我在服务器和客户端上都使用了 strace,它显示:服务器已收到请求并发送响应,客户端发送请求并继续等待响应。当它挂在那里时,我没有找到服务器正在回复的端口,在客户端执行 netstat 。这应该意味着什么?
您好像没有绑定客户端端口。绑定后,你可以使用getsockname
查看你得到的端口号。那么你也应该在netstat
中看到它。【参考方案2】:
只是猜测。尝试在“while”循环中从套接字读取。 类似的东西:
int received = 0;
int tmp;
int expected = ...
while(received != expected)
tmp = recvfrom(socket_id, msg_buffer, sizeof(msg_buffer), 0, (struct sockaddr *) &client_socket, &client_socket_len)
if(tmp == -1) ...
received += tmp;
【讨论】:
问题是我真的不知道我期待的消息的大小。事实上,我的应用程序中的工作流是基于这个可变大小的,所以我不能那样循环 recvfrom()。 特别是在消息大小不同的情况下,您必须使用 read() 或 recv() 的返回值。 @freieschaf:如果您不知道传入数据的大小,您将不得不忍受丢弃部分数据包,或者您将不得不分配一个缓冲区足够大以容纳可能的最大 UDP 数据包(64k,IIRC)。欢迎来到输入验证的世界。 @tbert:我的客户端和服务器都有固定最大大小的缓冲区。当他们接收到一个数据报时,他们使用接收到的数据的大小:如果是最大大小,他们继续接收;如果小于该大小,则传输结束。我认为那里没有任何问题,因为客户端还没有收到任何数据。以上是关于C中的两种方式UDP套接字的主要内容,如果未能解决你的问题,请参考以下文章