C++ Win套接字睡眠错误?
C++ Win socket sleep bug?
我在使用 TCP 将文件发送到下载的服务器时遇到了一点问题。我花了几个小时来找出问题所在,但仍然找不到它不起作用的原因。
主要问题是在我尝试发送文件时。程序得到了我的文件的字节数也读取了文件并循环通过条件,但它有时只发送文件。当我 运行 它通过调试器时,程序总是发送所有文件。当我使用 sleep() 1 秒时,问题也消失了。
#include <iostream>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
#include <windows.h>
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
SOCKET SendSocket;
SendSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SendSocket < 0) {
perror("Error at socket: ");
return 1;
}
struct sockaddr_in myAddr;
memset(&myAddr, '[=10=]', sizeof myAddr);
myAddr.sin_family = AF_INET; //IP4
myAddr.sin_port = htons(2000);
inet_pton(AF_INET, "127.0.0.1", &(myAddr.sin_addr));
memset(myAddr.sin_zero, '[=10=]', sizeof myAddr.sin_zero);
if (connect(SendSocket, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0)
{
perror("Error at connect: ");
return 1;
}
char buffer[512];
const char fileName[] = "test.txt";
FILE* fd;
if (errno_t a = fopen_s(&fd, fileName, "rb") != 0) {
perror("File not opened:");
return 1;
}
size_t bytes_read = 0;
size_t test = 0;
while (!feof(fd)) {
do {
if ((bytes_read = fread(buffer, 1, sizeof(buffer), fd)) < 0)
{
std::cout << "while error";
break;
}
else
{
//Sleep(1000);
if ((test = send(SendSocket, buffer, bytes_read, 0)) < 0) {
perror("Error send");
return 1;
}
//std::cout << "while send" << std::endl;
}
} while (test != bytes_read);
}
fclose(fd);
WSACleanup(); //clinap
system("PAUSE");
}
您需要更好地检查 send
的 return 值
https://linux.die.net/man/2/send
Return Value
On success, these calls return the number of characters sent.
有时,发送的缓冲区不足。剩下的不能直接丢弃,需要重新发送。
您还需要处理错误情况:
EAGAIN or EWOULDBLOCK The socket is marked nonblocking and the
requested operation would block. POSIX.1-2001 allows either error to
be returned for this case, and does not require these constants to
have the same value, so a portable application should check for both
possibilities.
这些人最有可能受到 Sleep
的影响。如果你睡了很多,你就不会得到这些错误,因为消息会在你睡觉时被刷新。当您不睡觉时,获得这些意味着您需要稍等 (Sleep(0)
),然后重试,直到获得正值 return。不要因为你得到过一次就出错了。
您的代码已损坏。 send
returns发送的字节数,可以小于bytes_read
。但是循环 while (test != bytes_read)
丢弃缓冲区内容并用新的 fread
.
填充它
您可以将其更改为在嵌套循环中调用 send
,直到发送整个缓冲区,但这在 TCP 帧方面效率低下 - 为获得最佳性能,需要结合使用 fread
和 send
在同一个循环中。
关于成帧 - 您的缓冲区太小 (512),建议发送大小为 1500(典型的最大 MTU)。
另请注意:您的 fread
错误处理已损坏。在 Win32 中 fread
return 值是无符号的,所以它永远不会是 < 0
.
应该是这样的(未测试):
char buffer[8192];
int bytes_in_buffer = 0;
for (;;) {
if (bytes_in_buffer < sizeof(buffer) / 2) {
int bytes_read = (int)fread(buffer + bytes_in_buffer, 1, sizeof(buffer) - bytes_in_buffer, fd);
if (bytes_read == 0) {
if (ferror(fd)) {
perror("fread");
return 1;
}
// at EOF now but continue
}
bytes_in_buffer += bytes_read;
}
if (bytes_in_buffer == 0) {
break; // all data is sent - done
}
int bytes_sent = send(SendSocket, buffer, bytes_in_buffer, 0);
if (bytes_sent < 0) {
perror("send");
return 1;
}
bytes_in_buffer -= bytes_sent;
if (bytes_in_buffer > 0 && bytes_sent > 0) {
memmove(buffer, buffer + bytes_sent, bytes_in_buffer);
}
}
此处可能的改进是使用环形缓冲区以减少复制。
我在使用 TCP 将文件发送到下载的服务器时遇到了一点问题。我花了几个小时来找出问题所在,但仍然找不到它不起作用的原因。
主要问题是在我尝试发送文件时。程序得到了我的文件的字节数也读取了文件并循环通过条件,但它有时只发送文件。当我 运行 它通过调试器时,程序总是发送所有文件。当我使用 sleep() 1 秒时,问题也消失了。
#include <iostream>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
#include <windows.h>
int main()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
SOCKET SendSocket;
SendSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SendSocket < 0) {
perror("Error at socket: ");
return 1;
}
struct sockaddr_in myAddr;
memset(&myAddr, '[=10=]', sizeof myAddr);
myAddr.sin_family = AF_INET; //IP4
myAddr.sin_port = htons(2000);
inet_pton(AF_INET, "127.0.0.1", &(myAddr.sin_addr));
memset(myAddr.sin_zero, '[=10=]', sizeof myAddr.sin_zero);
if (connect(SendSocket, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0)
{
perror("Error at connect: ");
return 1;
}
char buffer[512];
const char fileName[] = "test.txt";
FILE* fd;
if (errno_t a = fopen_s(&fd, fileName, "rb") != 0) {
perror("File not opened:");
return 1;
}
size_t bytes_read = 0;
size_t test = 0;
while (!feof(fd)) {
do {
if ((bytes_read = fread(buffer, 1, sizeof(buffer), fd)) < 0)
{
std::cout << "while error";
break;
}
else
{
//Sleep(1000);
if ((test = send(SendSocket, buffer, bytes_read, 0)) < 0) {
perror("Error send");
return 1;
}
//std::cout << "while send" << std::endl;
}
} while (test != bytes_read);
}
fclose(fd);
WSACleanup(); //clinap
system("PAUSE");
}
您需要更好地检查 send
https://linux.die.net/man/2/send
Return Value On success, these calls return the number of characters sent.
有时,发送的缓冲区不足。剩下的不能直接丢弃,需要重新发送。
您还需要处理错误情况:
EAGAIN or EWOULDBLOCK The socket is marked nonblocking and the requested operation would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
这些人最有可能受到 Sleep
的影响。如果你睡了很多,你就不会得到这些错误,因为消息会在你睡觉时被刷新。当您不睡觉时,获得这些意味着您需要稍等 (Sleep(0)
),然后重试,直到获得正值 return。不要因为你得到过一次就出错了。
您的代码已损坏。 send
returns发送的字节数,可以小于bytes_read
。但是循环 while (test != bytes_read)
丢弃缓冲区内容并用新的 fread
.
您可以将其更改为在嵌套循环中调用 send
,直到发送整个缓冲区,但这在 TCP 帧方面效率低下 - 为获得最佳性能,需要结合使用 fread
和 send
在同一个循环中。
关于成帧 - 您的缓冲区太小 (512),建议发送大小为 1500(典型的最大 MTU)。
另请注意:您的 fread
错误处理已损坏。在 Win32 中 fread
return 值是无符号的,所以它永远不会是 < 0
.
应该是这样的(未测试):
char buffer[8192];
int bytes_in_buffer = 0;
for (;;) {
if (bytes_in_buffer < sizeof(buffer) / 2) {
int bytes_read = (int)fread(buffer + bytes_in_buffer, 1, sizeof(buffer) - bytes_in_buffer, fd);
if (bytes_read == 0) {
if (ferror(fd)) {
perror("fread");
return 1;
}
// at EOF now but continue
}
bytes_in_buffer += bytes_read;
}
if (bytes_in_buffer == 0) {
break; // all data is sent - done
}
int bytes_sent = send(SendSocket, buffer, bytes_in_buffer, 0);
if (bytes_sent < 0) {
perror("send");
return 1;
}
bytes_in_buffer -= bytes_sent;
if (bytes_in_buffer > 0 && bytes_sent > 0) {
memmove(buffer, buffer + bytes_sent, bytes_in_buffer);
}
}
此处可能的改进是使用环形缓冲区以减少复制。