Reputation: 21
I have created a short class for socket communication and want so send and receive multiple times to the same device (here as an example www.kernel.org in my case its a sensor connected over ethernet). The communication is working with HTTP and I tested the device with "PacketSender" and it works fine.
For the first try I send the request and get the expected response. Then I want to loop it, but then I can send as much and as diffrent requests as I want and I get nothing.
Here is my class (I left it only as a draft in the H-File and will make it more decent when it works)
#ifndef SOCKETCLASS_H_INCLUDED
#define SOCKETCLASS_H_INCLUDED
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
class WinSocket{
private:
SOCKET s;
long rc;
int Status = 0;
int PackageSize = 10;
public:
WinSocket(){
rc=startWinsock();
if(rc!=0){
printf("Error: startWinsock failed, ErCode %d \n",int(rc));
Status= -1;
}else{
printf("Winsock ready!\n");
}
}
int openSocket(char *IPv4, int Port){
SOCKADDR_IN addr;
int rc = 0;
s = socket(AF_INET,SOCK_STREAM,0);
if(s==INVALID_SOCKET){
printf("Error: Socket could not be created! ErCode: %d\n",WSAGetLastError());
return 1;
}else{
printf("Socket created\n");
}
memset(&addr,0,sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;
addr.sin_port=htons(80);
addr.sin_addr.s_addr=inet_addr(IPv4);
rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
if(rc==SOCKET_ERROR){
printf("Error: Failed to connect, ErCode: %d\n",WSAGetLastError());
return 1;
}else{
printf("Connected to %s...\n",IPv4);
}
return 0;
}
int sendPackage(char *Buffer, int BufferSize){
int i,j;
int result;
int Pointer = 0;
char *Package;
Package = new char[PackageSize];
for(i = 0; i < BufferSize; i+=PackageSize){
for(j = 0; j < PackageSize; j++){
Package[j] = Buffer[Pointer];
Pointer++;
if(BufferSize <= Pointer){
break;
}
}
result = send(s,Package,PackageSize,0);
if(result<0){
printf("Error Occured!\n");
return -1;
}
}
delete[]Package;
return 0;
}
int readLine(char *Buffer, int *BufferSize){
int MAX_BUFFERSIZE = 1024;
int res = 0;
char B[1];
*BufferSize = 0;
int Pointer = 0;
for(int i=0;i<MAX_BUFFERSIZE;i++){
res = recv(s,B,1,0);
if(res > 0){
if(B[0]!='\n'){
//printf("%d;%s\n",res,B);
Buffer[Pointer] = B[0];
Pointer += 1;
}else{
Buffer[Pointer]='\n';
*BufferSize = Pointer;
return 0;
}
}else if(res == 0){
return 1;
}else{
return -1;
}
}
return 0;
}
int startWinsock(void){
WSADATA wsa;
return WSAStartup(MAKEWORD(2,0),&wsa);
}
~WinSocket(){
closesocket(s);
}
};
#endif // SOCKETCLASS_H_INCLUDED
As a main function i use the following code:
#include <stdio.h>
#include "SocketClass.h"
int main(){
char buf[256];
int i,j;
int requestSize = 100;
char request[100];
char Buf[1024];
int BufferSize = 1;
WinSocket S;
S.openSocket("147.75.44.153",80);
for(int l = 0; l<10; l++){
printf("Loop %d\n",l);
printf("Sending: ");
requestSize = sprintf(request,"GET /faq.html HTTP/1.1\r\nHost: www.kernel.org\r\nConnection: close\r\n\r\n");
printf("%d Bytes: \n",requestSize);
S.sendPackage(request,100);
for(j= 0; j < requestSize; j ++){
printf("%c",request[j]);
}
printf("\n");
Sleep(500);
printf("Waiting for responset...\n");
while(BufferSize!=0){
printf("Received: ");
S.readLine(Buf, &BufferSize);
printf("%d Bytes: \n",BufferSize);
for(int i=0;i<BufferSize;i++){
printf("%c",Buf[i]);
}
printf("\n");
}
if(BufferSize==0){
printf("\nNothing more received...\n");
}
printf("Repeat!\n");
Sleep(5000);
}
printf("Finished...\n");
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
I tested to open and close the socket every loop. This is sometimes working (so is there a non defined pointer I don't mentioned?), but I want a long duration of the connection.
What I do not understand is, why I can send multiple times but then receive only at the first sending any data.
I am using windows 7 and mingw (GNU GCC Compiler).
Thank you for your help.
Upvotes: 2
Views: 2612
Reputation: 597941
In your HTTP request, you are sending a Connection: close
header. That means the server WILL close its end of the TCP connection after sending the response. You are not detecting that condition so that you can close your current socket and re-connect to the server with a new socket on the next request.
You say you want the connection to remain open for multiple requests. That means you MUST utilize HTTP keep-alives (see RFC 2616 Section 8.1 and RFC 7230 Section 6.3). You need to remove the Connection: close
header from your request (as HTTP 1.1 uses keep-alives by default), or else replace it with an explicit Connection: keep-alive
header.
However, either way, you MUST read the response correctly (which you are not) in order to detect the correct end of the response (see RFC 2616 Section 4.4 and RFC 7230 Section 3.3.3) so you don't corrupt data between multiple responses on the same connection.
And you MUST pay attention to the Connection
header in the server's response, as there is no guarantee that the server will actually honor a request for a keep-alive. If the server sends an HTTP 1.0 response without an explicit Connection: keep-alive
header, or sends an HTTP 1.1 response with an explicit Connection: close
header, or otherwise sends a message whose length is denoted by the server being required to close the connection, you MUST close your current socket and reconnect with a new socket on the next request.
Upvotes: 1
Reputation: 1847
In the 2nd loop send()
returns an error for me: WSAECONNABORTED
.
Sockets are a real fun when it comes to errors, so you should check the real errors behind a failure of send()
etc with the real error numbers. Exchange the lines
if(result<0){
printf("Error Occured!\n");
return -1;
}
with
if(result < 0) {
printf( "Error Occured: %i\n", WSAGetLastError() );
return -1;
}
to get the real error.
WSAECONNABORTED
means that probably there's a timeout or something wrong with the protocol. Windows socket errors
I think this is caused by the server automatically disconnecting after fulfilling the request, so that there needs to be a new connection for each request. There is no persistent connection.
I looked in my own code and I did it in that order:
Besides of that, there seems to be some errors in your code.
E.g. in result = send(s,Package,PackageSize,0);
you always send 10 chars, even if the loop before was left because of if(BufferSize <= Pointer)
- this means you send some rubbish chars to the server. This can be avoided by
for(i = 0; i < BufferSize; i += PackageSize) {
int packageSize = 0;
for(j = 0; j < PackageSize; j++) {
Package[j] = Buffer[Pointer];
packageSize = Pointer;
Pointer++;
if(BufferSize <= Pointer) {
break;
}
}
result = send( s, Package, packageSize, 0 );
if(result < 0) {
printf( "Error Occured: %i\n", WSAGetLastError() );
return -1;
}
}
Upvotes: 0