2016-10-04 11 views
2

WinSock 2.2 send()関数は常に私に送信したいすべてのバイトを返します!私はポート80でgoogle.comに接続し、データのためにランダムにt文字を送信しています。私もtの1GBのものを送信しようとしました。それはまだ送信されたすべてのバイトで返されます。パケットに収まるバイト数と、実装のwhileループで処理される残りのバイト数を返すことを期待していましたが、結果としてwhileループの中に入ることはありませんでした。WinSock 2.2 TCP/IPv4 send()は常に送信されたすべてのバイトを返します

私はTCP/IPv4ソケットを使用しています。私は私のインターネットが私が点滅することができるよりも速く1GBを送るために速く点灯していないことを知っている。

このコードは、最も重要なチャンクについて示されています。例えば、私が示したsendを呼び出すC-string 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] = '\0'; 

//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; 
} 

EDIT 1

を送るラッパー

です

送るラッパー

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

EDITここ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] = '\0'; 

    //send ze data 
    int bytesSent = socket->send(buff); 

    //verify all ze data is sent 
    bool success = (bytesSent == strlen(buff)); 

    printf("requested bytes = %i\nsent bytes = \t %i", strlen(buff), bytesSent); 
    printf("\n\nsuccess = %s", success ? "true" : "false"); 

    closesocket(socketDescriptor); 
    delete socket; 
    freeaddrinfo(res); 
    WSACleanup(); 
    getchar(); 
    return 0; 
} 

EDIT 3

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

備考

...

正常に完了はありませんは、データが正常に配信され、受信者 に受信されたことを示します。この機能は、 を送信した場合にのみと表示されます。私はひどくそこwrittentているものを理解し What is the size of a socket send buffer in Windows?

しかし@Karstenクープは、関連する行動上の同様の問題を指摘しました。しかし、私が得たことは、関数が単にバッファに書き込んで、 "送信済みの"バイトを返すということです。これは受信者がデータを受け取ったことを保証していないことを意味するだけでなく(実際にはまったく送信されないことを意味します)、バッファ内にあります。私はここで何かを見逃しているのですか、またはその動作について誤解を招くマイクロソフトですか?

+0

'int bytesSent = socket-> send(buff);'長さを指定するのを忘れました。これはおそらく0として満たされていたので、コンパイラはバッファを最適化しました(使用したことがないため)。長さを過ぎてみてください。おそらく動作しますか? – LambdaBeta

+0

'socket-> send(buff、strlen(buff));' – Raindrop7

+0

@LambdaBeta no。そのためのラッパーがあります。私はそれに質問を更新しています。 – Infogeek

答えて

0

複数の種類のソケットがあります.Winsockは複数のプロトコルをサポートしています。

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)の現在の実装では、一般的に、すべてのデータが送信されるまでブロックしているようだという理由だけで、他のソケットタイプもブロックされることを意味するものではありません。

さらに、プロセスが中断された場合、sendはフルバッファより少ないデータを送信することがあります。またはソケットが他端か別のスレッドかのどちらかで閉じられているかどうかを確認します。

また、Winsock APIはBSDおよびPosixソケットAPIと互換性があるように設計されており、sendは通話中に信号が受信されるとエラーEINTRで返されます。 (Unixlandでは、ほとんどのブロッキングコールがerrno==EINTRで返ることがあります。これは、シングルスレッドシステムで外部イベントを処理する問題がどのように解決されたかを示しています)。

関連する問題