我是网络编程的初学者。我做了一个简单的UDP服务器和UDP客户端。客户端将消息发送到服务器,服务器打印消息。
一旦客户端停止发送消息,则recvfrom
方法被阻止。因此,我尝试使用fcntl
和select
创建一个非阻塞套接字,但它无效。
以下是我的UDP服务器代码。
#include "udpserver.h"
void start_udp_server(int PORT)
{
struct sockaddr_in server_addr ;
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
FD_ZERO(&master_fds);
FD_SET(sock_fd, &master_fds);
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET ;
server_addr.sin_addr.s_addr = htonl(0);
server_addr.sin_port = htons(PORT);
// bind the address with the socket
if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0)
fprintf(stderr , "error binding the socket to the address\n");
else
{
fprintf(stderr , "bind successful...\n");
fflush(stdout);
}
if (fcntl(sock_fd, F_GETFL) & O_NONBLOCK)
{
printf("\nsocket is non-blocking");
}
int r = fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFL) | O_NONBLOCK);
printf("r = %d",r);
if (r < 0)
{
printf("error making the socket non-blocking %d",r);
}
if (fcntl(sock_fd, F_GETFL) & O_NONBLOCK)
{
printf("\nsocket is non-blocking");
}
fprintf(stderr , "server listening on port %d %s\n",ntohs(server_addr.sin_port) ,inet_ntoa(server_addr.sin_addr));
fflush(stdout);
}
int receive_udp_msg()
{
socklen_t lengthOfClientAddress = sizeof(client_addr);
int activity = 0 ;
int l = 0 ;
FD_ZERO(&read_fds);
memcpy(&read_fds, &master_fds, sizeof(master_fds));
printf("before select\n");
activity = select(sock_fd + 1 , &read_fds, NULL, NULL, NULL);
printf("after select\n");
if (FD_ISSET(sock_fd, &read_fds))
{
printf("----activity happened on sock_fd\n");
l = (int)recvfrom(sock_fd, buffer, 1000, 0, (struct sockaddr *)&client_addr , &lengthOfClientAddress) ;
printf("received msg\n");
if (l == - 1)
{
fprintf(stderr , "there was error \n");
fflush(stdout);
return -1 ;
}
}
return l ;
}
int main()
{
start_udp_server ;
int l = 0 ;
while(1)
{
l = receive_udp_msg();
if(l > 0 )
print("message received : %s",buffer);
}
}
当客户端停止发送消息时,程序会打印before select
,之后不会打印任何内容。
答案 0 :(得分:3)
因为您对传递给timeout
的{{1}}指针使用NULL值,所以调用将阻塞,直到有套接字活动。
select
activity = select(sock_fd + 1 , &read_fds, NULL, NULL, NULL);
^
^
的手册页对此进行了详细说明。如果您不想这样做,请向select
调用一个非空指针,该指针指向填充了所需超时值的select
结构。