Can't receive the response package by winsock2 from http server - http

I'm sure my program has got the ip from the server by the url.
When I send the GET request, although it was successfully send, it couldn't get the response. I'm not sure if the server had gotten my request, how should I check if the server get my request?
The connection will close after sending a request and waiting for a period of time . The "recv" function will response 0, and the buffer get nothing.
I wonder if there are any error of my "sendbuf = GET / HTTP/1.1\r\n\r\n".
Should I use 1.1 or 1.0?
char *sendbuf = "GET / HTTP/1.1\r\n\r\n";
//to get the ip from DNS server
pHostEnt = gethostbyname( "www.google.com.tw");
ppaddr = (int**)pHostEnt->h_addr_list;
sockAddr.sin_addr.s_addr = **ppaddr;
printf("%s",inet_ntoa(sockAddr.sin_addr) );
//to create the socket and connect to it
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(inet_ntoa(sockAddr.sin_addr));
serverAddress.sin_port = htons(SERVER_PORT);
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
connect(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress));
//send request
int iResult = send( serverSocket, sendbuf, (int)strlen(sendbuf), 0 );
//get response
if (bytesRead=recv(serverSocket, buf, MAX_SIZE, 0) < 0)
printf("Error with send()");
else
printf("Successfully sent html fetch response");

Using HTTP 1.1 is fine, but your request is incomplete as HTTP 1.1 requires the Host header, at the very least (in order for servers to support virtual hosts).
More importantly, you are not doing any error handling. You need to do that.
You are also not taking into account that gethostname() can return multiple IP addresses. You need to connect() to each address until one succeeds, or until you exhaust the list.
Try this:
char *sendbuf = "GET / HTTP/1.1\r\nHost: www.google.com.tw\r\n\r\n";
//to get the ip from DNS server
pHostEnt = gethostbyname( "www.google.com.tw"); // you should be using getaddrinfo() instead!
if (!pHostEnd)
{
printf("Unable to resolve www.google.com.tw\n");
return; // or whatever...
}
if (pHostEnt->h_addrtype != AF_INET)
{
printf("www.google.com.tw did not resolve to an IPv4 IP address\n");
return; // or whatever...
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
printf("Unable to create socket\n");
return; // or whatever...
}
in_addr **ppaddr = (in_addr**) pHostEnt->h_addr_list;
sockaddr_in serverAddress = {0};
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(SERVER_PORT);
bool connected = false;
int i = 0;
while (ppadd[i] != NULL)
{
// connect to server
serverAddress.sin_addr = *(ppaddr[i]);
printf("Connecting to %s\n", inet_ntoa(serverAddress.sin_addr);
if (connect(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == 0)
{
connected = true;
break;
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(serverSocket, &writefds);
timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (select(0, NULL, &writefds, NULL, &timeout) > 0)
{
connected = true;
break;
}
}
++i;
}
if (!connected)
{
printf("Unable to connect to www.google.com.tw\n");
return; // or whatever...
}
printf("Connected, sending request\n");
//send request
char *ptr = sendbuf;
int len = strlen(sendbuf);
do
{
int bytesSent = send( serverSocket, ptr, len, 0 );
if (bytesSent > 0)
{
ptr += bytesSent;
len -= bytesSent;
continue;
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(serverSocket, &writefds);
timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (select(0, NULL, &writefds, NULL, &timeout) > 0)
continue;
}
printf("Unable to send request\n");
return; // or whatever...
}
while (len > 0);
printf("Reading response\n");
//get response
do
{
int bytesRead = recv(serverSocket, buf, MAX_SIZE, 0);
if (bytesRead > 0)
{
// process buf as needed...
// make sure you are paying attention to the
// Content-Length and Transfer-Encoding headers,
// as they tell you how to read the response.
// Refer to RFC 2616 Section 4.4 for details...
contine;
}
if (bytesRead == 0)
{
printf("Disconnected");
return; // or whatever...
}
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(serverSocket, &readfds);
timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
if (select(0, &readfds, NULL, NULL, &timeout) > 0)
continue;
}
printf("Unable to read response\n");
return; // or whatever...
}
while (true);
closesocket(serverSocket);

Related

Sending data over ESP_NOW

I'm a total noob and just starting out with PlatformIO and Arduino/ESP32. I also want to say thanks in advance to any help I can get.
Plan:
I have 2 ESP32's talking over ESP_NOW, I just can't verify the data being sent in order to progress with my project. Basically, I have a Nextion display that sends specific info to an ESP32 (tested and working) and that ESP32 is then to send that information via ESP_NOW to the other ESP32 which will translate it into serial data to send to an Arduino Due and perform some tasks.
Problem:
The issue I have is that when I test, I see the data I think I am transmitting, but when I try to Serial.print said info, I get "0 0 0 0". I'm not sure that I am sending OR receiving the data properly. All I know is that when I press the button on the Nextion, I get a response on the ESP32 that is not connected.
Code:
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
// Example to receive data with a start marker and length byte
// For ease of testing this uses upper-case characters A and B
// for the request and response types
// and Z for the start marker
// this version saves all the bytes after the start marker
// if the TYPE byte is wrong it aborts
const byte numBytes = 32;
byte receivedBytes[numBytes];
const byte typeBytePosition = 6; // Position after the start byte
const byte requestType = 0x65;
const byte requestLength = 7;
boolean newData = false;
int LED = 21;
// REPLACE WITH THE MAC Address of your receiver
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Define variables to store Nextion readings to be sent
byte NexEventID;
byte NexPageID;
byte NexObjectID;
byte NexStatusID;
// Define variables to store incoming readings// Define variables to store incoming readings
byte incomingEventID;
byte incomingPageID;
byte incomingObjectID;
byte incomingStatusID;
// Variable to store if sending data was successful
String success;
typedef struct struct_message
{
byte EventID;
byte PageID;
byte ObjectID;
byte StatusID;
} struct_message;
// Create a struct_message called NextionInfo to hold Nextion settings
struct_message NextionInfo;
// Create a struct_message called IncomingInfo to hold incoming info
struct_message IncomingInfo;
// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
if (status == 0)
{
success = "Delivery Success :)";
}
else
{
success = "Delivery Fail :(";
}
}
// Callback when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
{
struct_message *IncomingInfo = (struct_message *)incomingData;
Serial.println(WiFi.macAddress());
// memcpy(&IncomingInfo, incomingData, sizeof(IncomingInfo));
Serial.print("Bytes received: ");
Serial.println(len);
// incomingEventID = IncomingInfo.EventID;
Serial.print((byte)IncomingInfo->EventID, HEX);
Serial.print(' ');
// incomingPageID = IncomingInfo.PageID;
Serial.print((byte)IncomingInfo->PageID, HEX);
Serial.print(' ');
// incomingObjectID = IncomingInfo.ObjectID;
Serial.print((byte)IncomingInfo->ObjectID, HEX);
Serial.print(' ');
// incomingStatusID = IncomingInfo.StatusID;
Serial.println((byte)IncomingInfo->StatusID, HEX);
}
void emptyBuffer()
{
for (byte n = 0; n < numBytes; n++)
{
receivedBytes[n] = 0;
}
}
void recvBytesWithStartMarker()
{
static boolean recvInProgress = false;
static int ndx = -1;
static byte numBytesReceived = 0;
static byte mesgLen = 0;
const byte startMarker = 0x65;
byte rc;
while (Serial2.available() > 0 && newData == false)
{
rc = Serial2.read();
receivedBytes[numBytesReceived] = rc;
numBytesReceived++;
if (numBytesReceived > 33)
{
Serial.println("Error Rx : RESET !!");
Serial.println();
emptyBuffer();
numBytesReceived = 0;
newData = false;
}
if (recvInProgress == true)
{
if (numBytesReceived == typeBytePosition)
{
ndx = 0; // enable saving of data (anticipate good data)
if (rc == requestType)
{
mesgLen = requestLength;
}
else
{
recvInProgress = false; // abort - invalid request type
ndx = -1;
}
}
if (ndx >= 0)
{
ndx++;
}
if (numBytesReceived >= (mesgLen + typeBytePosition))
{ // got the whole message
recvInProgress = false;
newData = true;
}
}
else if (rc == startMarker)
{
emptyBuffer();
recvInProgress = true;
numBytesReceived = 0;
ndx = -1; // prevent counting valid bytes for the moment
}
}
}
// void getNexInfo()
// {
// NexEventID = receivedBytes[0];
// NexPageID = receivedBytes[1];
// NexObjectID = receivedBytes[2];
// NexStatusID = receivedBytes[3];
// // Serial.print(NexEventID&&NexPageID&&NexObjectID&&NexStatusID);
// }
void showNewData()
{
if (newData == true)
{
Serial.println(WiFi.macAddress());
Serial.print(requestType, HEX);
Serial.print(' ');
for (byte n = 0; n < typeBytePosition; n++) // n < numBytes
{
if (n == 0)
{
NexEventID = receivedBytes[n];
}
else if (n == 1)
{
NexPageID = receivedBytes[n];
}
else if (n == 2)
{
NexObjectID = receivedBytes[n];
}
else if (n == 3)
{
NexStatusID = receivedBytes[n];
}
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
}
//Serial.print(getNexInfo(),HEX);
Serial.println();
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&NextionInfo, sizeof(NextionInfo));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
newData = false;
}
}
void sendNewData()
{
// Set values to send
NextionInfo.EventID = NexEventID;
NextionInfo.PageID = NexPageID;
NextionInfo.ObjectID = NexObjectID;
NextionInfo.StatusID = NexStatusID;
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&NextionInfo, sizeof(NextionInfo));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
}
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(250000);
Serial2.begin(115200);
while (!Serial)
{
;
}
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
return;
}
// Register for a callback function that will be called when data is received
esp_now_register_recv_cb(OnDataRecv);
//Setup has completed
Serial.println("<ESP32 is ready>");
}
void loop()
{
recvBytesWithStartMarker();
showNewData();
}
Most of this has come from various tutorials across the web including YouTube and RandomNerdTutorials. I am by no means a master programmer, but I am trying to learn.
Here are the results I get from the serial monitors:
ESP32 1:
�<ESP32 is ready>
AC:67:B2:36:AA:A8
65 1 2 1 FF FF FF
Sent with success
Last Packet Send Status: Delivery Success
ESP32 2:
AC:67:B2:35:19:D8
Bytes received: 4
0 0 0 0
Note that I am only sending 4 bytes of info (65 1 2 1), so it seems to match up (I'm not sending FF FF FF)...
Thanks again for any help!!
I was able to resolve my issue. Below is the code that displayed the same information that was sent from the host and received by the slave ESP32.
#include <Arduino.h>
#include <esp_now.h>
#include <WiFi.h>
// Example to receive data with a start marker and length byte
// For ease of testing this uses upper-case characters A and B
// for the request and response types
// and Z for the start marker
// this version saves all the bytes after the start marker
// if the TYPE byte is wrong it aborts
const byte numBytes = 32;
byte receivedBytes[numBytes];
const byte typeBytePosition = 6; // Position after the start byte
const byte requestType = 0x65;
const byte requestLength = 7;
boolean newData = false;
int LED = 2;
// REPLACE WITH THE MAC Address of your receiver
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Variable to store if sending data was successful
String success;
struct __attribute__((packed)) dataPacket
{
byte EventID;
byte PageID;
byte ObjectID;
byte StatusID;
} packet, *packetPtr;
const dataPacket onLoc1R = {0x65, 0x01, 0x01, 0x01};
const dataPacket offLoc1R = {0x065, 0x01, 0x01, 0x00};
const dataPacket onLoc1L = {0x65, 0x01, 0x02, 0x01};
const dataPacket offLoc1L = {0x65, 0x01, 0x02, 0x00};
// Callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void emptyBuffer()
{
for (byte n = 0; n < numBytes; n++)
{
receivedBytes[n] = 0;
}
}
void recvBytesWithStartMarker()
{
static boolean recvInProgress = false;
static int ndx = -1;
static byte numBytesReceived = 0;
static byte mesgLen = 0;
const byte startMarker = 0x65;
byte rc;
while (Serial2.available() > 0 && newData == false)
{
rc = Serial2.read();
receivedBytes[numBytesReceived] = rc;
numBytesReceived++;
if (numBytesReceived > 33)
{
Serial.println("Error Rx : RESET !!");
Serial.println();
emptyBuffer();
numBytesReceived = 0;
newData = false;
}
if (recvInProgress == true)
{
if (numBytesReceived == typeBytePosition)
{
ndx = 0; // enable saving of data (anticipate good data)
if (rc == requestType)
{
mesgLen = requestLength;
}
else
{
recvInProgress = false; // abort - invalid request type
ndx = -1;
}
}
if (ndx >= 0)
{
ndx++;
}
if (numBytesReceived >= (mesgLen + typeBytePosition))
{ // got the whole message
recvInProgress = false;
newData = true;
}
}
else if (rc == startMarker)
{
emptyBuffer();
recvInProgress = true;
numBytesReceived = 0;
ndx = -1; // prevent counting valid bytes for the moment
}
}
}
void showNewData()
{
if (newData == true)
{
Serial.println(WiFi.macAddress());
Serial.print(requestType, HEX);
packet.EventID = requestType;
Serial.print(' ');
for (byte n = 0; n < typeBytePosition; n++) // n < numBytes
{
if (n == 0)
{
packet.PageID = receivedBytes[n];
}
else if (n == 1)
{
packet.ObjectID = receivedBytes[n];
}
else if (n == 2)
{
packet.StatusID = receivedBytes[n];
}
Serial.print(receivedBytes[n], HEX);
Serial.print(' ');
}
Serial.println();
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &packet, sizeof(packet));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
newData = false;
}
}
// Callback when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *data, int len)
{
Serial.println(WiFi.macAddress());
memcpy(&packet, data, sizeof(packet));
Serial.printf("%x %x %x %x\n",(byte) packet.EventID,(byte) packet.PageID,(byte) packet.ObjectID,(byte) packet.StatusID);
Serial.println();
}
void sendNewData()
{
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &packet, sizeof(packet));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
}
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(250000);
Serial2.begin(115200);
while (!Serial)
{
;
}
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
return;
}
// Register for a callback function that will be called when data is received
esp_now_register_recv_cb(OnDataRecv);
//Setup has completed
Serial.println("<ESP32 is ready>");
}
void loop()
{
recvBytesWithStartMarker();
showNewData();
}

recv() function return 0 and not able to reconnect with server when new socket created after time out

I have windows TCP client application which connect to port and server IP address.
it connect to server and working fine. this application send data in every 2 second to server and get response. some time in working application recv() does not get any response and return time out 10060 the we check continuously 3 time if any response on recv() function but it return 10060 time out every time.
then we close socket and create new socket to start new connection but at this time recv() will retirn 0 or 10054 error but not able to connect again with server.
//INIT TCP
WSADATA wsaData;
int iResult;
SOCKET ConnectSocket = INVALID_SOCKET;
*ConnectSocketOut = INVALID_SOCKET;
struct sockaddr_in clientService[MAX_PRINTERS];
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
return 1;
}
//----------------------
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); //IPPROTO_TCP
if (ConnectSocket == INVALID_SOCKET) {
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
clientService[Index].sin_family = AF_INET;
clientService[Index].sin_addr.s_addr = inet_addr(PortInformation[Index].IPAddress);
clientService[Index].sin_port = htons(PortInformation[Index].TCPPortNum);
//----------------------
// Connect to server.
WSASetLastError(0);
iResult = connect(ConnectSocket, (SOCKADDR*)&clientService[Index], sizeof(clientService[Index]));
if (iResult == SOCKET_ERROR) {
int ErrSt = WSAGetLastError();
closesocket(ConnectSocket);
WSACleanup();
ConnectSocket = INVALID_SOCKET;
*ConnectSocketOut = ConnectSocket;
return 1;
}
else
{
*ConnectSocketOut = ConnectSocket;
}
//send data
int iResult = 0;
if (ConnectSocketOut != INVALID_SOCKET)
{
DWORD timeout = 10 * 1000;
setsockopt(ConnectSocketOut, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
iResult = send(ConnectSocketOut, lpBuffer, (int)dNoOFBytestoWrite, 0);
}
else
{
return FALSE;
}
if ((iResult == SOCKET_ERROR)||(iResult!= dNoOFBytestoWrite)) {
int ErrorSt = WSAGetLastError();
closesocket(ConnectSocketOut);
WSACleanup();
ConnectSocketOut = INVALID_SOCKET;
return FALSE;
}
Status = TRUE;
//Receive data
int iResult = 0;
do {
if (ConnectSocketOut != INVALID_SOCKET)
{
DWORD timeout = 10 * 1000;
setsockopt(ConnectSocketOut, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
iResult = recv(ConnectSocketOut, (char*)&ReceiveData[BytesReceived], 100, 0);
}
if (iResult > 0)
{
BytesReceived += iResult;
Status = ReceiveData[BytesReceived - 1];
switch (Status)
{
case ACK:
case NAK:
{
AckStatus = ACK_FOUND;
break;
}
default:
{
Status = UNKNOW_ACK;
}
}
}
else if (iResult == 0)
{
int RetVal = WSAGetLastError();
Status = UNKNOW_ACK;
break;
}
else
{
int RetVal = WSAGetLastError();
}
}while ((AckStatus == ACK_NOTFOUND) && (Counter++ < 4));
if (Status == UNKNOW_ACK)
{
closesocket(ConnectSocketOut);
WSACleanup();
ConnectSocketOut = INVALID_SOCKET;
}
Sleep(1000);

C++ non-blocking TCP Server cannot send a message with more bytes than it received

I'm pretty new to network programing. I've written a simple non-blocking TCP Server using winsock2 but it behaves in a weird way that I couldn't find any example of it in previously asked questions.
My server can only send a message with as many bytes as it previously received. For example, if previously it received a "rec_msg", when I try to send "message_to_send" it only sends "message".
I don't if it has any effect but the server is encapsulated with a pure static class. Here are the function via a recieve and send message:
int TCPServer_Test::receiveMessage(){
while(1)
{
memset(recvbuf, 0, DEFAULT_BUFLEN);
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
int err = WSAGetLastError();
int counter = 0;
if (iResult > 0)
{
std::cout << "Mesaj Alindi: " << recvbuf << std::endl;
break;
}
else if(err == WSAEWOULDBLOCK)
{
Sleep(200);
continue;
}
else if (iResult == 0){
printf("Connection closing...\n");
return -1;
}
else
{
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
}
}
void TCPServer_Test::sendMessage(char* Source){
strncpy(recvbuf, Source, DEFAULT_BUFLEN);
iSendResult = send( ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
else if (iSendResult == 0) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
assert(false);
}
else
{
printf("Bytes sent: %d\n", iSendResult);
}
memset(recvbuf, 0, sizeof(recvbuf));
}
I would appreciate any help directly related or not.
It looks like it happens because you are using iResult variable that contains amount of data received during previous recv call when sending data instead of supplying real size of the data to be sent like this:
size_t bytes_count_to_be_send = strlen(Source);
iSendResult = send( ClientSocket, Source, bytes_count_to_be_send, 0);
Also notice that there is no real need to copy data into buffer.

Unix Client and Server Program - Very Odd Client and Server Socket Bug

I am currently making a client and server program in the Unix Environment. I have made it so the client is able to upload the contents of a file to the client. I am now in the process of adding options and error handlers to the server example the client must enter the file name. To do this i wanted to send a message saying OK if all the options checked out however if i do this it seems to cause my file reading and sending to go Crazy and I have no idea why.
I have uploaded the functions for doing this
Client Code
int putFile (char path[256], int fd)
{
char mystring[1000];
char buffer[100];
int i , n;
FILE * pFile;
n = read(fd,buffer,100);
printf("%s", buffer);
if (strcmp(buffer, "OK") == 0)
{
pFile = fopen(path, "r");
if(pFile != NULL)
{
while(fgets(mystring, sizeof(mystring), pFile) != NULL)
{
//fputs(mystring, fd);
write(fd,mystring,strlen(mystring));
}
}
else
{
printf("Invalid File or Address \n");
}
fclose(pFile);
}
else
{
printf("%s \n", buffer);
}
}
Server Code for reading the socket
int putRequest(int fd, char buf[], char str[])
{
char data[256];
int number;
char * ptr;
char results[100];
int total = 0;
char *arguments[1024];
char temp[10];
int i;
ptr = strtok(buf," ");
while (ptr != NULL)
{
char * temp;
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok (NULL, " ");
}
if(total == 1)
{
strcat(str, "Invaild Arguments \n");
return 1;
}
write(fd, "OK", 256);
FILE * pFile;
pFile = fopen ("myfile.txt","w");
if (pFile!=NULL)
{
while(read(fd, data, 256) != NULL)
{
fputs(data, pFile);
}
fclose (pFile);
}
else
{
strcat(str, "Invaild File");
return 0;
}
strcat(str, "Done");
return 1;
}
Thanks in advance and just post something if you need to see more code. I just placed the code which should be causing the problem.

Why recv() in winsock client cannot get any data once httpRetransmition happens?

I am trying to record the time between 'http request' package and 'http response' package.
I write an socket client using winsock. The code is below
if (send(sock, request.c_str(), request.length(), 0) != request.length())
die_with_error("send() sent a different number of bytes than expected");
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
response = "";
resp_leng= BUFFERSIZE;
http_leng= 381;
while(resp_leng==BUFFERSIZE||http_leng>0)
{
resp_leng= recv(sock, (char*)&buffer, BUFFERSIZE, 0);
http_leng= http_leng - resp_leng;
if (resp_leng>0)
response+= string(buffer).substr(0,resp_leng);
//note: download lag is not handled in this code
}
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
The code works nicely except one situation: HTTP Retransmition. I used wireshark to monitor packages and found out once there is a retransmition the code seems block on recv(), but cannot get any data from the socket buffer. I wonder why would this happen. Could somebody explain the reasons?
Any help will be appreciated.
Here is a second answer with more dynamic buffer handling and more error checking:
void send_data(SOCKET sock, void *data, unsigned int data_len)
{
unsigned char *ptr = (unsigned char*) data;
while (data_len > 0)
{
int num_to_send = (int) std::min(1024*1024, data_len);
int num_sent = send(sock, ptr, num_to_send, 0);
if (num_sent < 0)
{
if ((num_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
if (num_sent == 0)
die_with_error("socket disconnected");
ptr += num_sent;
data_len -= num_sent;
}
}
unsigned int recv_data(SOCKET sock, void *data, unsigned int data_len, bool error_on_disconnect = true)
{
unsigned char *ptr = (unsigned char*) data;
unsigned int total = 0;
while (data_len > 0)
{
int num_to_recv = (int) std::min(1024*1024, data_len);
int num_recvd = recv(sock, ptr, num_to_recv, 0);
if (num_recvd < 0)
{
if ((num_recvd == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("recv() failed");
}
if (num_recvd == 0)
{
if (error_on_disconnect)
die_with_error("socket disconnected");
break;
}
ptr += num_recvd;
datalen -= num_recvd;
total += num_recvd;
}
while (true);
return total;
}
std::string recv_line(SOCKET sock)
{
std::string line;
char c;
do
{
recv_data(sock, &c, 1);
if (c == '\r')
{
recv_data(sock, &c, 1);
if (c == '\n')
break;
line += '\r';
}
else if (c == '\n')
break;
line += c;
}
return line;
}
void recv_headers(SOCKET sock, std::vector<std::string> *hdrs)
{
do
{
std::string line = recv_line(sock);
if (line.length() == 0)
return;
if (hdrs)
hdrs->push_back(line);
}
while (true);
}
unsigned int recv_chunk_size(SOCKET sock)
{
std::string line = recv_line(sock);
size_t pos = line.find(";");
if (pos != std::string::npos)
line.erase(pos);
char *endptr;
unsigned int value = strtoul(line.c_str(), &endptr, 16);
if (*endptr != '\0')
die_with_error("bad Chunk Size received");
return value;
}
std::string find_header(const std::vector<std::string> &hrds, const std::string &hdr_name)
{
std::string value;
for(size_t i = 0; i < hdrs.size(); ++i)
{
const std::string hdr = hdrs[i];
size_t pos = hdr.find(":");
if (pos != std::string::npos)
{
if (hdr.compare(0, pos-1, name) == 0)
{
pos = hdr.find_first_not_of(" ", pos+1);
if (pos != std::string::npos)
return hdr.substr(pos);
break;
}
}
}
return "";
}
{
// send request ...
std::string request = ...;
send_data(sock, request.c_str(), request.length());
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
// get response ...
std::vector<std::string> resp_headers;
std::vector<unsigned char> resp_data;
recv_headers(sock, &resp_headers);
std::string transfer_encoding = find_header(resp_headers, "Transfer-Encoding");
if (transfer_encoding.find("chunked") != std::string::npos)
{
unsigned int chunk_len = recv_chunk_size(sock);
while (chunk_len != 0)
{
size_t offset = resp_data.size();
resp_data.resize(offset + chunk_len);
recv_data(sock, &resp_data[offset], chunk_len);
recv_line(sock);
chunk_len = recv_chunk_size(sock);
}
recv_headers(sock, NULL);
}
else
{
std::string content_length = find_header(resp_headers, "Content-Length");
if (content_length.length() != 0)
{
char *endptr;
unsigned int content_length_value = strtoul(content_length.c_str(), &endptr, 10);
if (*endptr != '\0')
die_with_error("bad Content-Length value received");
if (content_length_value > 0)
{
resp_data.resize(content_length_value);
recv_data(sock, &resp_data[0], content_length_value);
}
}
else
{
unsigned char buffer[BUFFERSIZE];
do
{
unsigned int buffer_len = recv_data(sock, buffer, BUFFERSIZE, false);
if (buffer_len == 0)
break;
size_t offset = resp_data.size();
resp_data.resize(offset + buffer_len);
memcpy(&resp_data[offset], buffer, buffer_len);
}
while (true)
}
}
::QueryPerformanceCounter(&httpResponseGot);
// process resp_data as needed
// may be compressed, encoded, etc...
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
}
You are not doing adequate error checking on the calls to send() and recv(). Try something like this instead:
char *req_ptr = request.c_str();
int req_leng = request.length();
int req_index = 0;
do
{
int req_sent = send(sock, req_ptr, req_leng, 0);
if (req_sent < 1)
{
if ((req_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
req_ptr += req_sent;
req_leng -= req_sent;
}
while (req_leng > 0);
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
std::string response;
int resp_leng = BUFFERSIZE;
int http_leng = -1;
bool http_leng_needed = true;
do
{
if (http_leng_needed)
{
std::string::size_type pos = response.find("\r\n\r\n");
if (pos != std::string::npos)
{
std::string resp_hdrs = response.substr(0, pos);
// look for a "Content-Length" header to see
// if the server sends who many bytes are
// being sent after the headers. Note that
// the server may use "Transfer-Encoding: chunked"
// instead, which has no "Content-Length" header...
//
// I will leave this as an excercise for you to figure out...
http_leng = ...;
// in case body bytes have already been received...
http_leng -= (response.length() - (pos+4));
http_leng_needed = false;
}
}
if (http_leng_needed)
resp_leng = BUFFERSIZE;
else
resp_leng = min(http_leng, BUFFERSIZE);
if (resp_leng == 0)
break;
resp_leng = recv(sock, buffer, resp_leng, 0);
if (resp_leng < 1)
{
if ((resp_leng == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
response += string(buffer, resp_leng);
if (!http_leng_needed)
http_leng -= resp_leng;
}
while ((http_leng_needed) || (http_leng > 0));
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
With this said, the "correct" way to handle HTTP in general is to read the inbound data line by line, rather than buffer by buffer, until you encounter the end of the response headers, then you can read the rest of the data buffer by buffer based on the data length indicated by the headers.

Resources