WinSock 2.2 TCP/IPv4 send()总是返回发送的所有字节

WinSock 2.2 TCP/IPv4 send() always returns all bytes sent

本文关键字:返回 字节 TCP IPv4 send WinSock      更新时间:2023-10-16

WinSock 2.2 send()函数总是返回我想要它发送的所有字节!我连接到google.com端口80和发送随机的t字母的数据。我甚至尝试发送多达1GB的t,它仍然返回所有发送的字节。我希望它能和我一起返回多少字节,它可以装在一个数据包中,其余的将由while循环在实现中处理,但它永远不会进入while循环内部!

我使用TCP/IPv4套接字。我知道我的网速不够快,发送1GB的速度比我眨眼的速度还快。

这段代码显示了大多数重要的块。例如,省略了c字符串send调用的包装器,它调用了我所示的send。

调用测试代码

//prepare the long data string
int buffSize = 1 * 1000 * 1000 * 1000;
char *buff = new char[buffSize];
memset(buff, 't', buffSize);
buff[buffSize - 3] = 'n';
buff[buffSize - 2] = 'n';
buff[buffSize - 1] = '';
//send thee data
int bytesSent = socket->send(buff);
//verify all thee data is sent
CHECK(bytesSent == strlen(buff));

发送implementatian

int mySocket::send(const void *data, int length)
{
    int bytesSent = ::send(socketDescriptor, (char*)data, length, 0);
    if (bytesSent == SOCKET_ERROR) return -1;
    while(bytesSent < length)
    {
        int sent = ::send(socketDescriptor, (char*)data + bytesSent, length - bytesSent, 0);
        if (sent == SOCKET_ERROR) return bytesSent;
        bytesSent += sent;
    }
    return bytesSent;
}

编辑1

因为它开始让人感到困惑这里是包装器

发送包装

int mySocket::send(const char * data_string)
{
    return send(dataString, strlen(data_string));
}

编辑2

是一个完整的工作示例,您可以调试。它产生相同的结果,它只是立即报告发送的所有字节。

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
class mySocket
{
public:
    mySocket(SOCKET sockeDesc)
    {
        socketDescriptor = sockeDesc;
    }
    int mySocket::send(const void *data, int length)
    {
        int bytesSent = ::send(socketDescriptor, (char*)data, length, 0);
        if (bytesSent == SOCKET_ERROR) return -1;
        while (bytesSent < length)
        {
            int sent = ::send(socketDescriptor, (char*)data + bytesSent, length - bytesSent, 0);
            if (sent == SOCKET_ERROR) return bytesSent;
            bytesSent += sent;
        }
        return bytesSent;
    }
    int mySocket::send(const char * data_string)
    {
        return send(data_string, strlen(data_string));
    }
private:
    SOCKET socketDescriptor;
};
int main()
{
    WSAData wsd;
    if (WSAStartup(MAKEWORD(2, 2), &wsd) || wsd.wVersion != MAKEWORD(2, 2))
    {
        WSACleanup();
        return 1;
    }
    //create ze socket
    SOCKET socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
    //look up socket info
    addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    addrinfo *res;
    int errCode = getaddrinfo("google.com", "80", &hints, &res);
    if (errCode) return 1;
    //connect ze socket
    int connectStatusCode = ::connect(socketDescriptor, res->ai_addr, res->ai_addrlen);
    if (connectStatusCode == SOCKET_ERROR) return 1;
    //create zeeeee socket!
    mySocket *socket = new mySocket(socketDescriptor);
    //prepare ze long data string
    int buffSize = 1 * 1000 * 1000 * 1000;
    char *buff = new char[buffSize];
    memset(buff, 't', buffSize);
    buff[buffSize - 3] = 'n';
    buff[buffSize - 2] = 'n';
    buff[buffSize - 1] = '';
    //send ze data
    int bytesSent = socket->send(buff);
    //verify all ze data is sent
    bool success = (bytesSent == strlen(buff));
    printf("requested bytes = %insent bytes = t  %i", strlen(buff), bytesSent);
    printf("nnsuccess = %s", success ? "true" : "false");
    closesocket(socketDescriptor);
    delete socket;
    freeaddrinfo(res);
    WSACleanup();
    getchar();
    return 0;
}

编辑3

https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506 (v = vs.85) . aspx

评论

发送函数的成功完成没有指示数据已成功地传递和接收到接收方。此函数仅指示数据成功 .

但是@Karsten Koop指出了有关相关行为的类似问题:Windows中套接字发送缓冲区的大小是多少?我不太明白上面写的是什么。但是我得到的是,它说函数只是写入缓冲区并返回"发送"的字节。但这不仅意味着它不能保证接收方收到了数据(微软说),而且意味着它实际上根本没有发送……只是在缓冲中。是我遗漏了什么,还是微软误导了自己的行为?

有多种类型的套接字:Winsock支持多种协议。

  • https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506 (v = vs.85) . aspx

仅仅因为socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)的当前实现通常似乎阻塞直到所有数据发送,并不意味着其他套接字类型也会阻塞。

此外,如果进程被中断,例如网络中断,或者套接字从另一端或被另一个线程关闭,send可能会发送少于满缓冲区的数据。

此外,Winsock API被设计为与BSD和Posix套接字API兼容,并且在这些平台上,如果在调用期间接收到信号,send通常会返回错误EINTR。(在Unixland中,大多数阻塞调用都可以使用errno==EINTR返回,这就是如何解决单线程系统上处理外部事件的问题)。