關於socket send recv 兩個函數各種錯誤說明


首先吐槽以下微軟的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中有簡單說明)真是坑啊。



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: