socket receive不能在for循环中
Socket receive can't be in for loop
我想以 32 位块发送 1GB 数据,所以在 for 循环中我正在做 send(client_sock, buffer, tinfo->bufferSize, 0);
这很好。但在那之后,我收到了在第一次迭代后抛出 error
(如下所示)的响应。如果我把 recv
放在 for loop
的外面,那么它就可以正常工作。但是这样我就无法确保每个块是否都正确发送了。
我的问题是
- 为什么我们不能迭代
receive
而我们可以迭代
send
?
- 可以不接收
for
吗?不用担心
关于是否每条消息都已发送?
N.B。 - 不能使用外部库,它是大学的 POC 项目。 'send 1 Gb of data in 32 bits chunk over socket'
void *tcpClient(void *arg) {
struct thread_info * tinfo = (struct thread_info *)arg;
char * buffer = (char *)malloc(sizeof(char)*(tinfo->bufferSize));
memset(buffer, 'a', sizeof(char)*(tinfo->bufferSize));
int client_sock = socket(AF_INET, SOCK_STREAM, 0);
connect(client_sock, (struct sockaddr *)&(tinfo->server_addr), sizeof(struct sockaddr));
long noOfChunks = oneGb/ tinfo->bufferSize;
for (int j = 0; j < noOfChunks; ++j) {
int totalBytesRcvd = 0;
int bytesRcvd = 0;
send(client_sock, buffer, tinfo->bufferSize, 0);
while (totalBytesRcvd < tinfo->bufferSize)
{
if ((bytesRcvd = recv(client_sock, buffer, tinfo->bufferSize, 0)) <= 0)
error("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
}
printf(buffer); /* Print the echo buffer */
}
free(buffer);
}
我遇到的错误:
Signal: SIGPIPE (signal SIGPIPE)
Terminated due to signal 13
Signal: SIGPIPE
当您写入已被对等方关闭的连接时发生。
那么,你的对端已经关闭了连接。
解决方法:不要。
在这里告诉您的所有关于 send()
程序崩溃或在阻塞模式下返回短计数的信息都是无稽之谈。 Posix 要求它阻塞,直到所有数据都被传输或发生错误,而这正是正在发生的事情。
1) @EJP 的回答几乎是正确的,但让我改一下。 "Socket receive can be in for loop",除了效率低下和糟糕的方法外,它没有任何问题。如果服务器在您的循环仍处于活动状态时关闭连接,您可能会收到 SIGPIPE
错误。
显而易见的可能解决方案是将 receive
保持在循环之外,因为如果每个块都已发送则不需要确认(在大多数情况下。)
2) 如果使用 TCP,可以在 for
之外保持接收,OS 将注意是否按顺序发送块并且没有块丢失。因此,即使我们将 receive
移到循环外也没有问题。
我想以 32 位块发送 1GB 数据,所以在 for 循环中我正在做 send(client_sock, buffer, tinfo->bufferSize, 0);
这很好。但在那之后,我收到了在第一次迭代后抛出 error
(如下所示)的响应。如果我把 recv
放在 for loop
的外面,那么它就可以正常工作。但是这样我就无法确保每个块是否都正确发送了。
我的问题是
- 为什么我们不能迭代
receive
而我们可以迭代
send
? - 可以不接收
for
吗?不用担心 关于是否每条消息都已发送?
N.B。 - 不能使用外部库,它是大学的 POC 项目。 'send 1 Gb of data in 32 bits chunk over socket'
void *tcpClient(void *arg) {
struct thread_info * tinfo = (struct thread_info *)arg;
char * buffer = (char *)malloc(sizeof(char)*(tinfo->bufferSize));
memset(buffer, 'a', sizeof(char)*(tinfo->bufferSize));
int client_sock = socket(AF_INET, SOCK_STREAM, 0);
connect(client_sock, (struct sockaddr *)&(tinfo->server_addr), sizeof(struct sockaddr));
long noOfChunks = oneGb/ tinfo->bufferSize;
for (int j = 0; j < noOfChunks; ++j) {
int totalBytesRcvd = 0;
int bytesRcvd = 0;
send(client_sock, buffer, tinfo->bufferSize, 0);
while (totalBytesRcvd < tinfo->bufferSize)
{
if ((bytesRcvd = recv(client_sock, buffer, tinfo->bufferSize, 0)) <= 0)
error("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
}
printf(buffer); /* Print the echo buffer */
}
free(buffer);
}
我遇到的错误:
Signal: SIGPIPE (signal SIGPIPE)
Terminated due to signal 13
Signal: SIGPIPE
当您写入已被对等方关闭的连接时发生。
那么,你的对端已经关闭了连接。
解决方法:不要。
在这里告诉您的所有关于 send()
程序崩溃或在阻塞模式下返回短计数的信息都是无稽之谈。 Posix 要求它阻塞,直到所有数据都被传输或发生错误,而这正是正在发生的事情。
1) @EJP 的回答几乎是正确的,但让我改一下。 "Socket receive can be in for loop",除了效率低下和糟糕的方法外,它没有任何问题。如果服务器在您的循环仍处于活动状态时关闭连接,您可能会收到 SIGPIPE
错误。
显而易见的可能解决方案是将 receive
保持在循环之外,因为如果每个块都已发送则不需要确认(在大多数情况下。)
2) 如果使用 TCP,可以在 for
之外保持接收,OS 将注意是否按顺序发送块并且没有块丢失。因此,即使我们将 receive
移到循环外也没有问题。