I'm trying to send a file from client to server using winsock2 lib.
After converting the file into char array, i'm sending this array using the send() command.
The problem: the data sent separately.
For e.g: I have file of size: 144429.
It does not send it at once, the data is split into many portions, like:
first send: 1460
second send: 21544
third send: 57136
etc..
until to whole data is sent.
so my question is: what causes it to send it by parts and not by once????
Solution I found working but not making any sense:
If i'm adding
cout << "bla bla bla";
before the send() function, it does work and send the whole 144429 by once. (but if the string given to cout is shorter, no change, send by parts)
CODE:
CLIENT SIDE
int Client::sendData(char *sendbuf, int length)
{
int iResult;
// if I remove those next few lines (until and including the cout line)
// the send will split.
char tmp[1];
// sent 1 dummy byte
iResult = send( _connectSocket, tmp, 1, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "SENDING DATA..." << endl;
// THIS IS THE RELEVANT AND ACTUAL DATA I WANT TO SEND
// send the data
iResult = send( _connectSocket, sendbuf, length, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "Data sent (" << iResult << " Bytes)" << endl;
return 0;
}
SERVER SIDE:
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int iResult = 0;
int totalBytesRead = 0;
// Receive until the peer shuts down the connection
do {
totalBytesRead += iResult;
iResult = recv(_clientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("RECEIVED DATA\n");
printf("Bytes received: %d\n", iResult);
} else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed: %d\n", WSAGetLastError());
closesocket(_clientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// store data into file
FileTransfer::binaryToFile(recvbuf, "doch.docx", totalBytesRead-1);
return 0;
}
There is no way to guarantee that send transmits some data as one unit - it just doesn't work that way. You have to add some extra information to tell the system that "Here's this much data to come" and/or "I'm done now". Even if you could convince your sending side to send of everything in one packet, assuming the receiving side isn't connected DIRECTLY with just a simple cable to the sender, you can't guarantee that the packet isn't broken up during it's passing through the network.
You just have to accept that if you are sending more than a single byte in a packet, you may have to call send multiple times. To simplify it, write a function that takes a an arbitrary size "whole packet" and calls send as many times as necessary... If you have a protocol that indicates the size of the data sent [such as in the first few bytes], you could have a receive function that does the same thing.
Depending on the socket type you are using there might be a limitation of data size in the underlying transport protocol.
In case you are using a network socket the size is limited by the maximum transfer unit (see: http://en.wikipedia.org/wiki/Maximum_transmission_unit).
If your data doesn't fit this size you will have to iterate in a loop sending portions of your data until either an error occurs or all data has been sent.
Related
Ive been trying to build an SNMP trap receiver using C++ and the winsock2 library, I have a thread set up to receive UDP data across port 161... as you would expect, when using a python socket program that i quickly threw together i was able to receive UTF-8 encoded strings and print them to the console. However, when i tried generating a SNMP Trap test event using iDRAC-9 (Dell server remote management tool), i managed to receive the 400 bytes as expected, but only printed 0é☺î☻☺. Frustratingly, the recvfrom() function can only take a char * parameter to receive the data. Im hoping to be able to decode roughly the same detail of data that Wireshark is capturing. Any help would be amazing!
code sample below:
int bytes_received = 0;
BYTE serverBuf[1025]{}; //1 Kilobyte + Null Terminating Character
int serverBufLen = 1024;
struct sockaddr_in SenderAddr {};
int SenderAddrSize = sizeof(SenderAddr);
do {
//Recieve Data
bytes_received = recvfrom(serverSocket, (char*)serverBuf, serverBufLen, 0, (SOCKADDR*)&SenderAddr, &SenderAddrSize);
if (bytes_received == SOCKET_ERROR) {
printf("recvfrom failed with error %d\n", WSAGetLastError());
bytes_received = 0;
}
//Make The String Null Terminated
serverBuf[bytes_received] = '\0';
std::cout << "Bytes Received: ";
std::cout << bytes_received << std::endl;
std::cout << serverBuf << std::endl;
//Send Data Back
char sendBuf[] = "Received\0";
if (sendto(serverSocket, sendBuf, (sizeof(sendBuf) - 1), 0, (SOCKADDR*)&SenderAddr, SenderAddrSize) == SOCKET_ERROR) {
printf("Sending back response got an error: %d\n", WSAGetLastError());
}
} while (active);
Wireshark Info
When attempting to read UDP packets using recvfrom the function returns -1 indicating an error. I of course then call WSAGetLastError to find out what the problem is. The reported error number is 183. I cant seem to find any reference as to what that number means.
Edit:
while (bytesRecv != SOCKET_ERROR)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
logError("Bytes recieved: ", bytesRecv);
// if data was recieved from the server
if (bytesRecv > 0)
{
//Data packet processing code
}
else
{
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
}
}
}
Edit:
void logError(const std::string &text, int errorCode)
{
std::ofstream log_file("error_log_file.txt", std::ios_base::out | std::ios_base::app);
log_file << text << errorCode << "\n";
}
The problem is not with WSAGetLastError() itself. The real problem is that you are calling logError() before calling WSAGetLastError(), and logError() ends up resetting the last error code to 183.
logError() uses a std::ofstream to open a file for appending. On Windows, that operation will ultimately call CreateFile() with the OPEN_ALWAYS flag, for which its documentation states:
Opens a file, always.
If the specified file exists, the function succeeds and the last-error code is set to ERROR_ALREADY_EXISTS (183).
If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero.
...
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
Internally, WSAGetLastError() simply maps to GetLastError() (a well-known but undocumented implementation detail). So, no matter whether the CreateFile() succeeds or fails in opening the file, the error code reported by WSAGetLastError() will get reset to the result of the open operation.
Your call to logError() is in the wrong place. It needs to be moved inside of your if (bytesRecv > 0) block (BTW, UDP supports 0-length datagrams, so you should be using >= instead of >):
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv >= 0)
{
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}
else // if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
}
Alternatively:
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}
So I need to receive a raw JSON string through a TCP connection.
I programmed a console application to receive the string. I tested the connection with telnet by sending text and it works fine. But when someone is sending me raw JSON strings I do not seem to receive anything. Is this because of the recv function?
Here is my code for receiving:
if ((new_socket = accept(s, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
puts("Connection accepted");
// Receive until the peer closes the connection
do {
iResult = recv(new_socket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
string input(recvbuf,iResult);
cout << input;
log << input;
}
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
}
I convert the input (recvbuf) to a string and print it to my console and to a log file. But when I use telnet it works fine, but if someone sends me raw JSON strings I seem to get no data. Is this a problem on my side (recv the wrong function or something?) or theirs? I tried using the read function but it creates a Assertion failed error.
I am trying to make a program that uses HTTP in winsock, but I have run into a problem where the recv function just hangs there.
int connect()
{
WSADATA t_wsa; //WSADATA structure
WORD wVers = 0x0202; //version number
int iError; //error number
wVers = MAKEWORD(2, 2); // Set the version number to 2.2
iError = WSAStartup(wVers, &t_wsa); // Start the WSADATA
if(iError != NO_ERROR || iError == 1)
{
printf("Error at WSAStartup()\n");
WSACleanup();
system("PAUSE");
return 1;
}
/* Correct version? */
if(LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2)
{
printf("Incorrect version\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKET sClient;
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET || iError == 1)
{
printf("Invalid Socket!\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKADDR_IN sinClient;
memset(&sinClient, 0, sizeof(sinClient));
char cIP[50];
strcpy_s(cIP, "98.139.183.24");
sinClient.sin_family = AF_INET;
sinClient.sin_addr.s_addr = inet_addr(cIP); // Where to start server
sinClient.sin_port = htons(80); //Port
if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR)
{
/* failed at starting server */
printf("Could not connect ot the server!\n");
WSACleanup();
system("PAUSE");
return 1;
}
// Now we can send/recv data!
printf("YOU ARE CONNECTED!\r\n");
string buffer;
buffer += "GET / HTTP/1.1\r\n";
buffer += "Host: http://www.yahoo.com/\r\n";
buffer += "Connection: close\r\n\r\n";
const char *cha = buffer.c_str();
int sent;
int response;
sent = send(sClient, cha, sizeof(cha) - 1, 0);
char recvbuf[50000];
response = recv(sClient, recvbuf, 50000, 0);
recvbuf[response] = '\0';
printf("\nReceived data = %s", recvbuf);
WSACleanup();
return(0);
}
"sent" will get printed after the send function, but nothing after recv gets printed.
What am I missing here?
A possible cause is that the send() is not sending the data intended:
sent = send(sClient, cha, sizeof(cha) - 1, 0);
the sizeof(cha) - 1 is actually sizeof(char*) - 1, not the actual length of the data: use buffer.length() instead.
Note that you can construct the std::string with the string literal in a single statement instead of constructing it via several concatentations. However, as the std::string is being used to obtain a const char* only there is no reason for using std::string at all:
const char* buffer = "GET / HTTP/1.1\r\n"
"Host: http://www.yahoo.com/\r\n"
"Connection: close\r\n\r\n";
sent = send(sClient, buffer, strlen(buffer), 0);
Check the return value of send() and recv() to determine success or failure, particularly recv() as the result is being used to index an array. On failure, recv() returns SOCKET_ERROR which (I think) is -1.
Handling HTTP responses correctly requires significant effort. The receiving code needs to examine the returned HTTP headers to determine how to handle the response content. For example, a HTTP response may be chunked or not. Libraries exist for managing HTTP requests, one is cpp-netlib (which was announced on isocpp.org circa February 2013).
I was reading this winsock example.
I am trying to conceptualize how you would create a C++ client program that has a persistent TCP/IP connection to a C# .NET server.
The problem I see is that in order for the C++ client to leave the receive loop, the server must close its socket connection to the client.
In my case the server will send to the client every couple seconds. I need to be able to receive one packet from the server and restart the main program loop so the client can perform the rest of its functionality.
If this receive code is in the C++ client's main loop, the client will never stop receiving if the server never closes the connection to the client:
// 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 with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
The example program that you have chosen to work from is designed to send a single request and receive a single response. It uses the state of the connection to indicate the end of the request, and the end of the response.
You might want to work from a different example program. Search for "winsock chat example" on google.
On the other hand, to modify this program as you have asked, you could replace the do-while loop with this:
// Assume that the OP's protocol sends 100-byte packets.
// Each while iteration attempts to receive one such packet.
// The while exits when the other side closes its connection.
while(1) {
// Receive 100-byte packet
int receivedBytes;
for(receivedBytes = 0; receivedBytes < 100; ) {
int iResult = recv(ConnectSocket,
recvbuf+receivedBytes,
recvbuflen-receivedBytes, 0);
if ( iResult > 0 ) {
receivedBytes += iResult;
printf("Bytes received: %d\n", iResult);
} else if ( iResult == 0 ) {
printf("Connection closed\n");
break;
} else {
printf("recv failed with error: %d\n", WSAGetLastError());
break;
}
}
if(receivedBytes == 100) {
// ... process packet here
} else {
break;
}
}
The problem here is that you have no way to know at what point recv() is going to return. There are five workarounds:
Make the socket non-blocking. (Not recommendable)
Use select() with a timeout.
Use async sockets. This is probably the fastest way, but more complex.
Use a thread.
BSD kqueue