So my problem is that when I use WinSock "send" in my do-while loop, PUTTY receives it twice.
char sendBuffer[] = "this is my message to the world";
do
{
iResult = recv(clientSocket, recvBuffer, DEFAULTBUFFERLEN, 0);
if(iResult > 0)
{
std::cout << "Received bytes: " << iResult << std::endl;
std::cout << recvBuffer << std::endl;
//Successful receive, now send back a message
Message("Now it's your turn to say something!");
//std::cin.getline(sendBuffer, DEFAULTBUFFERLEN);
std::cin.get();
iSendResult = send(clientSocket, sendBuffer, sizeof(sendBuffer), 0);
if(iSendResult == SOCKET_ERROR)
{
Message("Error with send. ERROR: " + WSAGetLastError());
closesocket(clientSocket);
WSACleanup();
return 8;
}
std::cout << "Bytes sent: " << iSendResult << std::endl;
}
else if(iResult == 0)
{//Nothing has been received, client has disconnected
Message("Closing connection with client");
}else
{// there was an errror and the connection needs to be closed
Message("Error Receiving. Error: " + WSAGetLastError());
closesocket(clientSocket);
WSACleanup();
return 9;
}
}while(iResult > 0);
The code works otherwise works well, compiles and overall, goes smoothly, the only problem is that the send call sends it twice for some reason.
I call send once before this only to say "Welcome to the server" but that actually only sends once. It's only the one in this bit that sends twice.
I'm using mingw to compile and this is my build script
g++ server.cpp -o server -lws2_32 -lwsock32
Edit: According to my debugger, the code runs once when it receives an initial message from the client but then runs again and is receiving "\r\n" when it runs again, hence the repeated message without waiting for a new client message
So after some debugging I found out the problem, putty sends a an extra message when you press enter(or something to this effect. So the solution was to wrap the code handling received messages with an if statement with these conditions:
if((std::string)recvBuffer != "\r\n" || (std::string)recvBuffer != "\n")
Related
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;
my select function is returning -1 in my server code and on checking error code its returning 10038 which has this description in documentation:-
WSAENOTSOCK
10038
Socket operation on nonsocket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
My code:
nRet = select(nSocket + 1, &fr, &fw, &fe, &tv);
if (nRet > 0)
{
//someone connects or communicates with a message over a dedicated connection
std::cout << "data on port\n";
ProcessRequest();
}
else
{
if (nRet == 0)
{
//No connection or any communication made or you can say that none of the descriptors
//are ready
std::cout << "nothing on port:" << PORT << "\n";
}
else
{
//it failed to connect
std::cout << "it failed" << nRet << "\n";
error = WSAGetLastError();
std::cout << "error: " << error << "\n";
WSACleanup();
exit(EXIT_FAILURE);
}
}
just for clearing socket(),setsockopt(),bind() and listen() calls were successful as they returned 1
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.
I'm working on a client application that sends sensor data one way to a remote server. After the initial login there is no return data from the server. My problem is when the ethernet is disconnected such as a hard disconnect i.e. wireless link goes down, my application does not get a error return value after attempting a 'send' call. I am using a single non-blocking socket instance. The thread checks for a 'recv' each loop using 'select'. It does eventually get an error on 'recv' but never on 'send'.
When the remote PC has a internet connectivity loss it will cause the program to be disconnected from the server for minutes to hours before it recognises the connection loss happened and switches to re-login the server. What can be done to help detect the hard disconnect?
void checkConnect(NTRIP& server)
{
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
if(FD_ISSET(server.socket, &Reader) )
{
int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
if(recvBytes == SOCKET_ERROR)
{
cout << "socket error on receive call from server " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else if(recvBytes == 0)
{
cout << "server closed the connection gracefully" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else //>0 bytes were received so read data if needed
{
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "select returned socket in error state" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select socket error " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect if no other data has been sent recently
if(server.connected_IP == true && getTimePrecise() - server.lastDataSendTime > 5.0)
{
char buf1[] = "hello";
cout << "checking send for error" << endl;
iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "server send WSAEWOULDBLOCK" << endl;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out " << iResult << " bytes" << endl;
}
server.lastDataSendTime = getTimePrecise();
}
}
It is not possible to detect disconnect until you try to send something.
The solution for you is the following:
You detect that you have received no data for a certain period of time and you want to check is the connection is alive.
You send some data to the server using send function. It could be protocol-specific ping packet or either garbage. The send function returns immediately, because it does not wait for actual data send. It only fills internal send buffer.
You begin waiting for socket read.
While you are waiting, OS tries to send the data in the send buffer to the server.
When OS detects that it cannot deliver data to the server, then the connection is marked as erroneous.
Now you will get an error when calling recv and send functions.
The send timeout is system specific and can be configured. Usually, it is about 20 seconds (Linux) - 2 minutes (Windows). It means that you need to wait a lot before you receive an error.
Notes:
You can also turn on TCP keep alive mechanism, but I don't recommend you to do this.
You can also modify TCP timeout intervals. It can be helpful when you want the connection to survive the temporary network disconnect.
That's how TCP works and is intended to work. You will get an error from a subsequent send, but never from the first send after the disconnect. There is buffering, and retry, and retry timeout to overcome before an error is signalled.
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.