Winsock Received buffers caracters - c++

I am currently trying to create an application to send messages from a server to a client after initiating the connection by sending filters from the client to the server (like a subscrition). The entire application is done but I found out that the messages I send contain special caracters and dont have the size they are supposed to have. Here is an example with the filters (which are 3 letter words) that the server receives:
Client connected!
Bytes received: 3
REceived Filters:ATL����������������������
Although it says that 3 bytes were received, it prints 25 caracters.
Here is the server side part of the code I use to receive the filters:
// Receiving and sending data on server socket
int iSendResult;
// buffer for received msg
char recvbuf[3];
int recvbuflen = 3;
int compteurSend = 1;
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
{
printf("\nBytes received: %d\n", iResult);
printf("REceived Filters:");
std::cout << recvbuf << "\n" << std::endl;
}
...... rest of the code to send back data ......
And here is the client side part of the code I use to send te filters:
// Sending and receiving data
// buffer for sending filters
const char* sendbuf = "ATL";
int sendbuflen = strlen(sendbuf);
// buffer for receiving
char recvbuf[4000];
int recvbuflen = sizeof(recvbuf);
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, sendbuflen, 0);
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
std::cout << "Filters Sent: " << "'" << sendbuf << "'" << " containing " << iResult << " bytes\n\n";
While the output of the cout on the client part is correct, stating " Filters Sent: 'ATL' containing 3 bytes ", I can only understand that the issue comes from the server side and the alocation of the buffer size. Did I miss anything or did I mess up on the use of sizeof and strlen.

std::cout << recvbuf is treating recvbuf as a null-terminated char* string, but there is no null terminator being sent by the client, and no null terminator being inserted by the server after the data received. So, operator<< ends up reading past the valid data, which is why you are seeing extra garbage being printed.
So, you can either:
update the client to send the null terminator (just make sure the server's recvbuf is large enough to receive it):
const char* sendbuf = "ATL";
int sendbuflen = strlen(sendbuf) + 1; // <-- here
add a null terminator artificially on the server side:
char recvbuf[4];
do {
iResult = recv(ClientSocket, recvbuf, sizeof(recvbuf)-1, 0);
if (iResult > 0)
{
recvbuf[iResult] = '\0'; // <-- here
printf("\nBytes received: %d\n", iResult);
printf("Received Filters:");
std::cout << recvbuf << "\n" << std::endl;
}
since recv() tells you how many bytes are actually received, simply use ostream::write() instead of operator<<, eg:
std::cout.write(recvbuf, iResult);
std::cout << "\n" << std::endl;

Related

How to correctly response to HTTP request

I am trying to create simple server which will repond to every HTTP request with 200 OK. I write code below, but when I called the server with Postman I ended with wrong result. If I do NOT call closesocket(clientSocket), Postman is waiting infinitely long for response with Sending requst.... I i do call closesocket(clientSocket), Postman shows Error: socket hang up.
What I have to do to correctly close connection?
void main()
{
std::cout << "Start..." << std::endl;;
int port = 54000;
// Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
std::cout << "Can't start Winsock, Err #" << wsResult << std::endl;
return;
}
// Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "Can't create socket, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(sock, (sockaddr*)&hint, sizeof(hint));
listen(sock, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
// While loop: accept and echo message back to client
char buf[16384];
while (true)
{
SOCKET clientSocket = accept(sock, (sockaddr*)&client, &clientSize);
//print(client);
ZeroMemory(buf, 16384);
// Wait for client to send data
int bytesReceived = recv(clientSocket, buf, 16384, 0);
if (bytesReceived == SOCKET_ERROR)
{
std::cout << "Error in recv(). Quitting" << std::endl;
break;
}
const char* reply =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Content-Length: 0\n"
"Keep - Alive: timeout=1, max=1\n"
"Accept-Ranges: bytes\n"
"Connection: close\n";
send(clientSocket, reply, strlen(reply), 0);
//closesocket(clientSocket);
} |
}
edit. Edited code. I corrected line endings, added better check for recv result and also I am checking number of sent bytes (and yes, all bytes are send). I also tried to add shutdown function, but result is still the same - infinite waiting or error. When I try to add do / while section, I will stuck in infinite waiting for another request. Do you have any other advice?
void main()
{
std::cout << "Start..." << std::endl;;
int port = 54000;
// Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
std::cout << "Can't start Winsock, Err #" << wsResult << std::endl;
return;
}
// Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "Can't create socket, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(sock, (sockaddr*)&hint, sizeof(hint));
listen(sock, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
// While loop: accept and echo message back to client
char buf[16384];
while (true)
{
SOCKET clientSocket = accept(sock, (sockaddr*)&client, &clientSize);
//print(client);
ZeroMemory(buf, 16384);
// Wait for client to send data
//do {
bytesReceived = recv(clientSocket, buf, 16384, 0);
if (bytesReceived > 0)
{
std::cout << std::string(buf, 0, bytesReceived) << std::endl;
}
else if (bytesReceived == 0)
{
std::cout << "Connection closed" << std::endl;
}
else
{
std::cout << "Error in recv(). Quitting = " << WSAGetLastError() << std::endl;
break;
}
//} while (bytesReceived > 0);
const char* reply =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 0\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: close";
bytesSent = send(clientSocket, reply, strlen(reply), 0);
if (bytesSent < 0)
{
std::cout << "Send failed = " << WSAGetLastError() << std::endl;
}
std::cout << "Sent: " << bytesSent << " (" << strlen(reply) << ")" << std::endl;
shutdown(clientSocket, SD_BOTH);
closesocket(clientSocket);
} |
}
const char* reply =
"HTTP/1.1 200 OK\n"
...
"Keep - Alive: timeout=1, max=1\n"
...
"Connection: close\n";
send(clientSocket, reply, strlen(reply), 0);
This is not a valid HTTP response for multiple reasons:
The line ending should be \r\n not \n.
The HTTP header should end with an additional \r\n (i.e. empty line). This means the HTTP response you send is not complete and thus Postman hangs on waiting for the rest.
The Keep - Alive header has not the valid syntax for a HTTP header. The field name is not allowed to contain spaces.
Apart from that,
send is not guaranteed to send everything in the given buffer, i.e. you should check the return code.
A Keep-Alive header makes no sense at all if Connection: close is used.
Note that HTTP is not an ad-hoc protocol but an actual standard. Implementations should follow the standard and thus the developers would need to study the actual standard and not blindly rely on (wrong) assumptions of how things might work. Even if it works with some client it might not work with another one, since some clients adhere more to the standard while others are more tolerant regarding errors.
There are multiple problems with the shown code.
int bytesReceived = recv(clientSocket, buf, 16384, 0);
On any TCP socket, HTTP or not, you get no guarantees whatsoever that whatever the other side of the socket sent you, it will get returned in a single recv() call.
If, for example, the client sent you the following HTTP request:
GET / HTTP/1.0<CR><LF>
Host: localhost<CR><LF>
<CR><LF>
Nobody is going to guarantee you that this recv() will return this entire thing to you. recv() could, for example, return only the "GET" part, and return the value of 3 to indicate that only 3 bytes were received. You are required to call recv() as many times as necessary to receive the complete message. The 2nd call to recv() could, theoretically, return " /" and the value of 2 to indicate that two more bytes were received.
You cannot completely ignore the return code from recv(), which tells you what was actually read, and you will need to implement appropriate logic to keep recv()ing until you received the entire message. Your code needs to understand that an HTTP message consists of a message line, an arbitrary list of headers, then a single blank line, all terminated by <CR><LF>, or "\r\n", and keep trying until it receives the complete message.
const char* reply =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Content-Length: 0\n"
"Keep - Alive: timeout=1, max=1\n"
"Accept-Ranges: bytes\n"
"Connection: close\n";
HTTP uses <CR><LF> as the end of line terminator, all of these should be \r\n.
"Keep - Alive:" is not a valid HTTP header name. Header names cannot contain spaces.
A blank line, a single \r\n, should follow the last HTTP header. It is missing fom your response. Even though you're closing the socket immediately, without a well-formed HTTP response message the client can rightfully conclude that the HTTP server is faulty and did not send a valid response.
send(clientSocket, reply, strlen(reply), 0);
Like with recv(), you are not guaranteed that send() will transmit the requested number of bytes. Just like with recv() you must check the return value of send() to see how many bytes were sent, and then try again to send the remaining part of the message, if there's any, until you send the entire message.
You must fix all of these problems in order to properly implement HTTP over TCP.

Socket server receiving data at buffer size

I send packets of different sizes one after the other, how can I receive the packets separately at the size I send, not cumulated in the buffer. It seems that now the server adds to the buffer until it fills it and then I can process them.
Example:
Buffer size: 84.
Send from client: 84 bytes, 76 bytes, 76 bytes, 80 bytes
Receive in server: 84 bytes, 84 bytes, 84 bytes, 64 bytes.
I would like to receive them as I sent them. Is it possible?
int port = stoi(getConfig("server_port"));
std::string ipAddress = getConfig("ip_address");
// Create a socket
int listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening < 0){
std::cerr << "Can't create a socket!" << endl;
Logger("Can't create a socket!");
exit(-1);
}
std::cout << "The socket server was created successfully." << endl;
// Bind the socket to a IP / port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
if (bind(listening, (sockaddr*)&hint, sizeof(hint)) < 0){
cerr << "Can't bind to IP/port!" << endl;
Logger("Can't bind to IP/port!");
exit(-1);
}
// Mark the socket for listening in
if (listen(listening, SOMAXCONN) < 0){
cerr << "Can't listen!" << endl;
Logger("Can't listen!");
exit(-1);
}
// Accept a call
sockaddr_in client;
socklen_t clientSize = sizeof(client);
char host[NI_MAXHOST];
char svc[NI_MAXSERV];
while(true){
int clientSoket = accept(listening, (sockaddr*)&client, &clientSize);
if(clientSoket < 0){
cerr << "Problem with client connecting!" << endl;
Logger("Problem with client connecting!");
break;
}
cout << "The client whas conected successfully." << endl;
memset(host, 0, NI_MAXHOST);
memset(svc, 0, NI_MAXSERV);
int result = getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, svc, NI_MAXSERV, 0);
if(result == 0) {
cout << host << " connected on " << svc << endl;
} else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on " << ntohs(client.sin_port) << endl;
}
// While receiving
char buff[84];
while(true){
// Clear the buffer
memset(buff, 0, sizeof(buff));
// Wait for a message
int bytesRecv = recv(clientSoket, buff, sizeof(buff), 0);
if(bytesRecv < 0){
cerr << "There was a connection issue!" << endl;
Logger("There was a connection issue!");
break;
}
if(bytesRecv == 0){
cout << "The client disconnected." << endl;
Logger("The client disconnected");
break;
}
cout << "bytesRecv: " << bytesRecv << endl;
}
// Close the socket
close(clientSoket);
}
No, stream sockets don't work that way.
A stream socket is an unstructured byte stream, without any structure to it, whatsoever. In this respect it is no different from a plain file. If you wrote your records, of varying sizes, to a plain file and you are now prepared to read them back, how do you expect to read the your variably-sized records?
Whichever answer you give here, the same answer applies to sockets, with the additional twist that a read() on a socket offers you no guarantees whatsoever as to how much you'll read, except that it'll be less than or equal to the size parameter to read(). That's the only warranty you'll get from read().
If the sender called write() twice (and, by the way, sockets also don't guarantee that however much you want to write, that much gets written, write can also return a byte count less than or equal to its size parameter, and it's up to your code to figure out how to deal with it), once writing 76 bytes and the second time with 84, read()ing that (assuming a sufficiently large buffer size) can read any number of bytes between 1 and 160 bytes, on the initial read.
If you wish to implement some formal structure, records of some kind, it is up to you to figure out how to implement it within these constraints. Maybe by sending the size of each record, in bytes, followed by the record itself. Or do whatever you want. Just keep in mind that you have no guarantees, whatsover, how much an individual read() returns. If, for example, you're sending the record count first, as a four byte value. Your initial read() may return one, two, or three bytes. Your code must be prepared to handle any eventuality.

WinSock C++ Console App Instant Messanger recv doesn't block

I have a question regarding WinSock library.
I'm trying to write simple instant messages program. I wrote it only for 2 clients, and now i would like to improve it, so It can work for many of them, and each client would sent an message with its number and number of the client which will recieve message to the server.
Ive got a problem and I can't figue out, why such simple thing doesnt work:
Code of the client function that sends the messages:
void cClientIO::GetID(SOCKET & socket)
{
u_long iMode = 0;
ioctlsocket(socket, FIONBIO, &iMode);
cout << "Type your ID:" << endl;
cin >> buffer;
send(socket, buffer, sizeof(buffer), 0);
cout << "Type reciever ID" << endl;
cin >> buffer;
//We send buffer to the server;
send(socket,buffer,sizeof(buffer), 0);
}
//Here is the server side:
void cRunServer::GetClientInfo(SOCKET & s){
char buffer[256];
int iResult;
//BLOKUJ pls
u_long iMode = 0;
iResult = ioctlsocket(s, FIONBIO, &iMode);
recv(s, buffer, sizeof(buffer), 0);
cout << "Client number: " << buffer << WSAGetLastError() << endl;
iResult = ioctlsocket(s, FIONBIO, &iMode);
recv(s, buffer, sizeof(buffer), 0);
cout << "Attempts to connect to client ID: " << WSAGetLastError() << endl;
}
I dont know what is going on...
The first recv block my code, but the second one doesnt, and just goes on...
I tried to use GetWSALastError() but it gives me 0 all the time...
Thanks for help in advance.
It doesn't work because the size of the buffers does not match. Client is sending char[2048] and I recv only char[256] and the second call gets the rest of the buffer, and thats why it continues to flow.

winsock recv() duplicates/missing data

I'm writing a simple server/client program to send a file from client to server.
i'm using winsock2. I'm limiting the capacity to send the data each time to 5000.
client side (send):
int iResult = 0;
int totalBytesSent = 0;
while (length > 0){
iResult = send( _connectSocket, data, MAX_TRANSIT_SIZE, 0 ); // MAX_TRANSIT_SIZE is 5000
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
totalBytesSent += iResult;
length -= iResult;
//cout << "Data sent (" << iResult << " Bytes)" << endl;
}
cout << "Total Bytes Sent: (" << totalBytesSent << ")" << endl;
return 0;
on the server side (recv):
// Receive and send data
char recvbuf[MAX_DATA_SIZE];
int iResult = 0;
int totalBytesRead = 0;
// Receive until the peer shuts down the connection
do {
totalBytesRead += iResult;
iResult = recv(_clientSocket, recvbuf, MAX_DATA_SIZE, 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);
cout << "Total Bytes Received: (" << totalBytesRead << ")" << endl;
The problem:
After running client and server and sending a file, it does say the correct data size sent/received (which is of course the file size in bytes), BUT the output file is different, and when I open it with some text editor (notepad++) I can clearly see that the output file holds less data (but File->Properties shows same file sizes) and some data is duplicates.
My Question:
How do revc() works? If it's receiving data in many calls, does it accumulates it in the buffer? (In my case: recvbuf) or does it rewrite the buffer?
As far as I figured out, it does accumulate, so my code is correct??
Thanks.
There are several issues in your code.
Client side:
send( _connectSocket, data, MAX_TRANSIT_SIZE, 0 );
Here you never update data to account for the bytes already sent, so every time you call send it sends the same data again and again (the first MAX_TRANSIT_SIZE bytes of your data buffer). A quick fix, assuming data is a pointer to any byte type (uint8_t, char, ...) would be:
send( _connectSocket, data + totalBytesSent, MAX_TRANSIT_SIZE, 0 );
You should also cap the data size you send, because unless length is originally a multiple of MAX_TRANSIT_SIZE you'll have a buffer overrun when you reach the end of the data:
send( _connectSocket, data + totalBytesSent, std::min(length, MAX_TRANSIT_SIZE), 0 );
Server side:
recv(_clientSocket, recvbuf, MAX_DATA_SIZE, 0);
Just like with send, recv has no notion of "what did I already receive in that buffer". So every time you call recv it just put the new data it receives at the beginning of your buffer, overwriting the older data. This may or may not be what you want, this is hard to tell since you don't show us how you use that buffer. You may want to use the same approach to manage your receive buffer than the one I just explained for your send buffer.
I don't see where you're writing out of the recvbuf. Each time you call recv it is going to overwrite what is already in the recvbuf. Therefore, where you have the commented out "RECEIVED DATA" prints, you should be copying the data you want to keep out of the buffer.

C++ Server not displaying the packet

I'm making a server in C++ winsock
Right now I'm trying to debug and see what packet the client sent.
Here is my code
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
(...)
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
cout << "The packet is: " << hex << recvbuf << endl;
But on the console when the client has connected the display is just:
The packet is:
Nothing is displayed. What am I missing?
If I do:
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
(...)
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
cout << "The packet size: " << iResult << endl;
//result is "The packet size: 10"
Now I want to see what that packet is.
UPDATE
I tried this:
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
string packet = recvbuf;
cout << "The packet is: " << packet.c_str() << endl;
Still no strings returned. just "The packet is: "
The bytes you receive in that buffer might be non-printable, and might be not zero-terminated. Print them as integers, say, with hexadecimal format, in a loop from 0 to iResult - 1.
Edit 0:
The important part is that you need to print exact number of bytes. Something as simple as the following would do (unsigned char to avoid sign-extension of values larger then 127):
unsigned char buf[BSIZE];
// ... get data of size iResult
for ( int i = 0; i < iResult; i++ ) {
printf( "%02x ", buf[i] );
}
printf( "\n" );