我有一个服务器守护程序侦听TCP unix域/本地套接字。在同一台计算机上运行的多个客户端连接到它。守护程序也绑定到UDP Internet套接字。只要守护程序从其中一个本地客户端接收任何数据,它就会将相同的数据发送到除发送客户端之外的所有连接的客户端。如果守护程序在UDP Internet套接字上接收数据,则需要将该数据发送到所有本地连接的客户端。当守护进程在本地套接字上接收数据时,数据的发送/接收工作正常。但是,当服务器向UDP Internet套接字发送数据时,客户端不会收到任何数据。客户端在退出服务器守护程序并关闭连接后,或者当任何客户端在本地向服务器发送数据时,都会收到该Internet数据。客户端连同本地数据一起接收互联网数据。我使用fcntl()
将local和inet套接字设置为阻塞。这是我的守护进程代码(我删除了所有不必要的代码):
while(1)
{
FD_SET(sockfd, &read_fds);
FD_SET(inet_sock, &read_fds);
for (i = 0; i < nclients; i++)
{
FD_SET(clients[i], &read_fds);
}
select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL);
/* Check for events on inet sock */
if (FD_ISSET(inet_sock, &read_fds))
{
/* Read from inet sock */
socklen = sizeof(dest_sin);
rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT,
(struct sockaddr *) &dest_sin, &socklen);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
}
}
/* A read event on the local socket is a new connection */
if (FD_ISSET(sockfd, &read_fds))
{
socklen = sizeof(dest_sun);
/* Accept the new connection */
rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen);
/* Add client to list of clients */
clients[nclients++] = rval;
if (rval > maxfd) maxfd = rval;
snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0",
nclients, rval);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
}
/* Check for events from each client */
for (i = 0; i < nclients; i++)
{
fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]);
/* Client read events */
if (FD_ISSET(clients[i], &read_fds))
{
fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]);
/* Read from client */
rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
/* Skip the sender */
if (j == i) continue;
/* Send the message */
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
}
}
}
}
以下是我的客户端代码:
while(1)
{
FD_SET(fileno(stdin), &read_fds);
FD_SET(sockfd, &read_fds);
select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1,
&read_fds, &write_fds, &except_fds, NULL);
if (FD_ISSET(sockfd, &read_fds))
{
/* Read from socket and display to user */
mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT);
buf[mlen]=0;
printf("Received %d bytes: %s", mlen, buf);
}
if (FD_ISSET(fileno(stdin), &read_fds))
{
fgets(buf, BUFLEN, stdin);
fprintf(stderr, "Sent %d octets to server.",
send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0));
}
}
目标是让客户端立即接收守护程序发送的数据(守护程序在其inet套接字上接收的数据)。
编辑:我认为当守护进程发送数据时,客户端的select()返回套接字是可读的,但是recv()是阻塞的,这就是我的原因。没有在客户端获取数据。有关如何解决此问题的任何建议吗?
答案 0 :(得分:1)
以下是代码中的send()
调用,已提取并对齐:
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
我在这里看到一些不一致的地方。有时您会使用两个参数调用strlen()
,有时strnlen()
,有时strlen()
(我甚至不知道该怎么做)。
您遇到的问题可能与您没有在套接字上发送任何信息有关,这些信息显示了消息之间的界限。在流套接字上,消息边界不保留,您应该注意在协议中包含适当的成帧信息,以便接收方可以提取单个消息。与recv()
调用中的send()
调用相比,您不能依赖与{{1}}调用完全相同的字节数。您将以相同的顺序获得相同的总字节数(这是流套接字的点),但消息可能会合并或拆分,您无法控制它。