关于socket send recv 两个函数各种错误说明

来源:互联网 发布:数据库软件哪个好 编辑:程序博客网 时间:2024/06/04 08:33

首先吐槽以下微软的socket的两个最重要的API:send函数和recv函数,本菜鸟感觉这两个函数是用来给程序员自己开发的函数,用起来跟翔一样的体验。

int recv(  _In_  SOCKET s,  _Out_ char   *buf,  _In_  int    len,  _In_  int    flags);

int send(  _In_       SOCKET s,  _In_ const char   *buf,  _In_       int    len,  _In_       int    flags);

这是这两个函数的原型,参数含义我就不解释了,这里面常见的两种错误:

1、发送长度问题。这是个老生常谈的问题,在send一串字符的时候应该首先发送这串字符的长度n,然后才能在recv的时候recv(HANDLE , recvstring , n , 0);

2、还是发送长度的问题。在现实程序中发现一个问题,当发送长度过大时候,经常一次recv不够完全,需要多次recv才能接收完全,经常发现send 10000个字符,recv返回的接收字符串长度小于10000。这时候就应该这样写

int cSocket::SendBits(char * s , int bytes){int sendbytes = 0;while(sendbytes < bytes)  //实际发送长度小于应该发送长度</span>{sendbytes+= send( hSocket , (char *)(s+sendbytes) , bytes-sendbytes , 0 );}return sendbytes;}int cSocket::RecvBits(char *& s , int bytes){int recvbytes = 0;while(recvbytes < bytes)  //实际接收长度小于应该接收长度{recvbytes += recv( hSocket , s+recvbytes , bytes-recvbytes , 0 );}return recvbytes;}
再来对比以下MSDN上面的例子

#define WIN32_LEAN_AND_MEAN#include <winsock2.h>#include <Ws2tcpip.h>#include <stdio.h>// Link with ws2_32.lib#pragma comment(lib, "Ws2_32.lib")#define DEFAULT_BUFLEN 512#define DEFAULT_PORT "27015"int __cdecl main() {    //----------------------    // Declare and initialize variables.    WSADATA wsaData;    int iResult;    SOCKET ConnectSocket = INVALID_SOCKET;    struct sockaddr_in clientService;     char *sendbuf = "this is a test";    char recvbuf[DEFAULT_BUFLEN];    int recvbuflen = DEFAULT_BUFLEN;      //----------------------    // Initialize Winsock    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);    if (iResult != NO_ERROR) {      printf("WSAStartup failed: %d\n", iResult);      return 1;    }    //----------------------    // Create a SOCKET for connecting to server    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (ConnectSocket == INVALID_SOCKET) {        printf("Error at socket(): %ld\n", WSAGetLastError() );        WSACleanup();        return 1;    }    //----------------------    // The sockaddr_in structure specifies the address family,    // IP address, and port of the server to be connected to.    clientService.sin_family = AF_INET;    clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );    clientService.sin_port = htons( 27015 );    //----------------------    // Connect to server.    iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );    if ( iResult == SOCKET_ERROR) {        closesocket (ConnectSocket);        printf("Unable to connect to server: %ld\n", WSAGetLastError());        WSACleanup();        return 1;    }    // Send an initial buffer    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );    if (iResult == SOCKET_ERROR) {        printf("send failed: %d\n", WSAGetLastError());        closesocket(ConnectSocket);        WSACleanup();        return 1;    }    printf("Bytes Sent: %ld\n", iResult);    // shutdown the connection since no more data will be sent    iResult = shutdown(ConnectSocket, SD_SEND);    if (iResult == SOCKET_ERROR) {        printf("shutdown failed: %d\n", WSAGetLastError());        closesocket(ConnectSocket);        WSACleanup();        return 1;    }    // Receive until the peer closes the connection    do {        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);        if ( iResult > 0 )            printf("Bytes received: %d\n", iResult);        else if ( iResult == 0 )            printf("Connection closed\n");        else            printf("recv failed: %d\n", WSAGetLastError());    } while( iResult > 0 );    // cleanup    closesocket(ConnectSocket);    WSACleanup();    return 0;}
MSDN在处理recvbuf的时候任然没有判断iResult和recvbuflen之间的关系。为整个程序埋下了隐患。(其实在MSDN remark中有简单说明)真是坑啊。


0 0