I am implementing a communication system (tx, rx) using TCP, in windows 10. My problem is when tx sends a message to rx, the message is received with delay. When tx sends several messages, the rx starts receiving only after several messages are sent. My guess is that tx waits until its buffer gets full and then starts sending messages altogether (in my platform buffer length is 512).
As shown in the bellow picture, before receiving is started, this error appears:
ERROR receiving TCP, error #: 10014
I tried to solve this problem by enabling the TCP_NODELAY option so that the messages are being sent immediately (which was not successful). However, my knowledge of TCP is shallow and I am not sure if I am doing it correctly.
Here are my questions:
Does the delayed sending (or receiving) is related to the TCP_NODELAY option of the TCP?
If yes, am I enabling the TCP_NODELAY correctly as follows:
int yes = 1;
int resultt = setsockopt(serverSocket[0], IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(int)); // 1 - on, 0 - off
if (resultt < 0)
std::cerr << "Error: TCP_NODELAY";
Am I putting the TCP_NODELAY option in the right place in both server and client codes?
Here are my codes for client:
size_t IPTunnel::ipTunnelSend_tcp(size_t process) {
size_t remaining = process;
size_t result{ 0 };
size_t sent{ 0 };
while (remaining > 0) {
result = send(clientSocket[0], &(ip_tunnel_buffer[0]) + sent, (int) remaining, 0);
if (result >= 0) {
remaining -= result;
sent += result;
}
else {
if (getLogValue()) {
if ( result == 0) std::cerr << "No data send through TCP" << std::endl;
else std::cerr << "ERROR sending TCP, error #: " << WSAGetLastError() << std::endl;
}
break;
}
}
return sent;
}
and:
bool IPTunnel::client_tcp() {
// STEP 1 - Initialize Winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0)
{
std::cerr << "Can't start Winsock. Error code #" << wsResult << std::endl;
return false;
}
// STEP 2 - Create a socket
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
int yes = 1;
int resultt = setsockopt(clientSocket[0], IPPROTO_TCP, TCP_NODELAY, (char*)&yes,
sizeof(int));
if (resultt < 0)
std::cerr << "Error: TCP_NODELAY";
clientSocket.push_back(s);
if (clientSocket[0] == INVALID_SOCKET)
{
std::cerr << "Can't create socket, Error Code #" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
// STEP 3 - Connect to the server
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons((u_short)localMachinePort);
inet_pton(AF_INET, remoteMachineIpAddress.c_str(), &hint.sin_addr);
int connResult{ -2 };
while (connResult != 0 || numberOfTrials == 0) {
connResult = connect(clientSocket[0], (sockaddr*)& hint, sizeof(hint));
if (connResult == SOCKET_ERROR)
{
std::cerr << "Can't connect to server, Err #" << WSAGetLastError() << std::endl;
std::cerr << "Waiting " << timeIntervalSeconds << " seconds." << std::endl;
Sleep(timeIntervalSeconds * 1000);
}
if (--numberOfTrials == 0) {
std::cerr << "Reached maximum number of attempts." << std::endl;
}
}
std::cerr << "Connected!\n";
return true;
}
Here are my codes for server:
size_t IPTunnel::ipTunnelRecv_tcp(size_t space) {
char* recv_buffer = &ip_tunnel_buffer[0];
size_t remaining{ 0 };
if (outputSignals[0]->getValueType() == (signal_value_type::t_message))
{
remaining = ip_tunnel_buffer.size();
}
else
{
remaining = space * outputSignals[0]->valueTypeSizeOf();
}
size_t received{ 0 };
while (remaining > 0) {
auto aux{ 0 };
aux = recv(serverSocket[1], recv_buffer + received, (int) remaining, 0);
if (aux > 0) {
received += aux;
remaining -= received;
}
else {
if (getLogValue()) {
if (aux == 0) std::cerr << "No data received through TCP" << std::endl;
else std::cerr << "ERROR receiving TCP, error #: " << WSAGetLastError() << std::endl;
}
break;
}
}
return received;
}
and:
bool IPTunnel::server_tcp() {
// STEP 1 - Initialize Winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0)
{
std::cerr << "Can't start Winsock. Error code #" << wsResult << std::endl;
return false;
}
// STEP 2 - Create a socket
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
serverSocket.push_back(s);
if (serverSocket[0] == INVALID_SOCKET)
{
std::cerr << "Can't create socket, Error Code #" << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
// STEP 3 - Bind the socket
sockaddr_in hint;
hint.sin_family = AF_INET; // AF_INET=2, IPv4
inet_pton(AF_INET, localMachineIpAddress.data(), &hint.sin_addr.S_un.S_addr);
hint.sin_port = ntohs((u_short)localMachinePort);
char ipAddress[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &hint.sin_addr.S_un.S_addr, ipAddress, INET_ADDRSTRLEN);
std::cerr << "The TCP server is running on IP address: " << ipAddress;
std::cerr << " Port: " << htons(hint.sin_port) << std::endl;
if (bind(serverSocket[0], (sockaddr*)& hint, sizeof(hint)) < 0) {
std::cerr << "Bind failed with error code #" << WSAGetLastError() << std::endl;
return false;
}
// STEP 4 - Listen on the socket for a client
if (listen(serverSocket[0], SOMAXCONN) == -1) {
std::cerr << "Listen error!" << std::endl;
return false;
}
// STEP 5 - Accept a connection from a client
sockaddr_in client;
int clientSize = sizeof(client);
s = accept(serverSocket[0], (sockaddr*) &client, &clientSize);
serverSocket.push_back(s);
// Provides information
char host[NI_MAXHOST];
char service[NI_MAXSERV];
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)& client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
std::cerr << host << " connected on port " << service << std::endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::cerr << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
int yes = 1;
int resultt = setsockopt(serverSocket[0], IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(int)); // 1 - on, 0 - off
if (resultt < 0)
std::cerr << "Error: TCP_NODELAY_Server";
return true;
}
Here are the codes for sending the message (tx):
bool LoadFromCommandWindow::runBlock(void) {
int space = outputSignals[0]->space();
if (!space) return false;
if (flag && flag1)
{
std::getline(std::cin, plainData);
}
if (plainData.length() == 0)
{
flag = false;
return false;
}
else
{
data = plainData.substr(k, paddedDataLength);
if (data.length() != paddedDataLength) paddedData = padTo(data, paddedDataLength, '\0');
else paddedData = data;
outputSignals[0]->bufferPut((std::byte*) paddedData.c_str(), paddedDataLength); \\ This line puts the message into buffer
k += data.length();
if (k != plainData.length()) flag1 = false;
else
{
flag1 = true;
k = 0;
}
}
return flag;
}
std::string LoadFromCommandWindow::padTo(std::string str, const size_t num, const char paddingChar = '\0')
{
if (num > str.size())
str.insert(str.size(), num - str.size(), paddingChar);
return str;
}
Here are the codes for receiving the message (rx):
bool PrintData::runBlock(void) {
int ready = inputSignals[0]->ready();
int space = outputSignals[0]->space();
int process = std::min(ready, space);
if (process == 0) return false;
inputSignals[0]->bufferGet((std::byte*)decryptedData, decryptedDataLength);
decryptedDataLength = unpad(decryptedDataLength, decryptedData, '\0');
for (size_t i = 0; i < decryptedDataLength; i++)
{
std::cout << decryptedData[i];
}
std::cout << std::endl;
outputSignals[0]->bufferPut((std::byte*)decryptedData, decryptedDataLength);
decryptedDataLength = 496;
return true;
}
Thank you!
socket should be
int data_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
it should be enough , but it depends
bulletproof stuff is to use whole buffer transfers with buffer size on system maximum
https://stackoverflow.com/a/64726689/7172363
Related
I'm trying to build a multithread HTTP server using C++ and winsock2.h and sys/socket.h.However, after sending response successfully to first request, accept() function captures other requests and sends through thread pool but those threads hangs up in recv() function so function can never capture data from socket.Here is my code.
void HTTPServer::init()
{
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(0x202,&wsaData);
if((mSock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
#else
if((mSock = socket(AF_INET,SOCK_STREAM,0)) < 0)
#endif
{
std::cout << "Error while initilazing socket\n";
}
mServerAddr.sin_family = AF_INET;
mServerAddr.sin_port = htons(mPort);
#ifdef _WIN32
mServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;
#else
mServerAddr.sin_addr.S_addr = INADDR_ANY;
#endif
if(bind(mSock, (struct sockaddr*) &mServerAddr, sizeof(mServerAddr)) < 0)
{
std::cout << "Error while binding socket\n";
}
if(listen(mSock, SOMAXCONN))
{
std::cout << "Error while listening socket\n";
}
}
void HTTPServer::fRun()
{
ThreadPool* tPool = new ThreadPool(10);
while(1)
{
int size = sizeof(mClientAddr);
#ifdef _WIN32
if((mAcceptSocket = accept(mSock,(struct sockaddr*) &mClientAddr,&size)) == INVALID_SOCKET)
#else
if((mAcceptSocket = accept(mSock,(struct sockaddr*) &mClientAddr,&size))) < 0)
#endif
{
std::cout << "Error while initilazing accept socket\n";
}
std::cout << "Socket Sent " << mAcceptSocket << std::endl;
tPool->enqueue([&] { this->fOnRequest(mAcceptSocket); });
}
delete tPool;
}
void HTTPServer::fOnRequest(uint64_t socket)
{
const string reqData = fRecieveNext(mAcceptSocket);
const HTTPResponse res = fProcessRequest(reqData);
fSendResponse(res,socket);
std::cout << "Done";
}
const string HTTPServer::fRecieveNext(uint64_t socket)
{
int64_t recieveLength = 0,totalRecieved = 0;
int64_t recieveLengthBeforeBody = -1;
int contentLength = 0;
string rawData;
while(1)
{
memset(mBuffer,'\0',8192);
if((recieveLength = recv(socket,mBuffer,8192, 0)) == SOCKET_ERROR)
{
std::cout << "Error while receiving data from socket\n";
#ifdef _WIN32
std::cout << WSAGetLastError() << std::endl;
#endif
break;
}
if(recieveLength == 0)
break;
totalRecieved += recieveLength;
rawData += string(mBuffer,recieveLength);
if(totalRecieved > 32)
{
if(rawData.find("Content-Length") == string::npos && contentLength == 0)
break;
else
{
if(contentLength == 0)
{
auto pos = rawData.find("Content-Length:");
auto lengthStr = rawData.substr(pos + 16, rawData.find_first_of("\r",pos) - pos - 16);
contentLength = std::stoi(lengthStr);
}
if(rawData.find("\r\n\r\n") != string::npos && recieveLengthBeforeBody == -1)
{
recieveLengthBeforeBody = rawData.find("\r\n\r\n") + 4;
}
if(totalRecieved >= contentLength + recieveLengthBeforeBody)
break;
}
}
}
return rawData;
}
void HTTPServer::fSendResponse(const HTTPResponse& response,const uint64_t socket)
{
string resStr = response.fSerializeResponse();
size_t sent = 0,totalSent = 0;
char* buffer = &(resStr[0]);
while(totalSent < resStr.length())
{
if((sent = send(socket, buffer, resStr.length() - totalSent,0)) < 0)
{
std::cout << "Error while sending response" << std::endl;
}
buffer += sent;
totalSent += sent;
}
delete &response;
#ifdef _WIN32
if(shutdown(socket, SD_BOTH) == SOCKET_ERROR)
{
std::cout << "Error while closing socket" << std::endl;
std::cout << WSAGetLastError() << std::endl;
};
if(closesocket(socket) == SOCKET_ERROR)
{
std::cout << "Error while closing socket" << std::endl;
std::cout << WSAGetLastError() << std::endl;
};
#else
if(shutdown(socket, SHUT_RDWR) < 0)
{
std::cout << "Error while closing socket" << std::endl;
};
if(close(socket) < 0)
{
std::cout << "Error while closing socket" << std::endl;
};
#endif
}
It looks like you are expecting to receive a TCP message all in one recv. TCP doesnt work like that. Tcp is a stream protocol, a message sent to you can be broken into multiple chunks. TCP only guarantees that the bytes will arrive once and in the correct order.
That would make you get out of sync with the input
void TCPConnectionV5::startServer()
{
/* Initialize Winsock */
int start;
sockaddr_in SERVER;
SERVER.sin_family = AF_INET;
SERVER.sin_addr.s_addr = INADDR_ANY;
//SERVER.sin_port = htons(stoi(DEFAULT_PORT));
SERVER.sin_port = htons(1787);
start = WSAStartup(MAKEWORD(2, 2), &_wsaData);
if (start != 0)
{
cout << "Error on WSAStartup: " << start << endl;
}
/* Create socket that will connect to server */
_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
_socketCollection.push_back(_listener);
if (_listener == INVALID_SOCKET)
{
cout << "Error creating socket to connect to server: " << WSAGetLastError() << endl;
WSACleanup();
}
/* Bind the socket */
start = bind(_listener, (sockaddr*)&SERVER, sizeof(SERVER));
if (start == SOCKET_ERROR)
{
cout << "Error on bind:" << WSAGetLastError() << endl;
closesocket(_listener);
WSACleanup();
}
/* Create the listener socket */
start = listen(_listener, 16);
if (start == SOCKET_ERROR)
{
cout << "Error on entering the listening state: " << start << endl;
closesocket(_listener);
WSACleanup();
}
printTime();
cout << "Server entered listening state" << endl;
/* Create the thread */
sockaddr_in client;
int clientSize = sizeof(client);
while (true)
{
SOCKET messager = accept(_listener, (struct sockaddr*)&client, &clientSize);
_socketCollection.push_back(messager);
locker.lock();
printTime();
if (messager != SOCKET_ERROR)
{
cout << "Client Connection success!" << endl;
cout << "Messager: " << messager << endl;
locker.unlock();
std::thread newThread([&] {this->exchange(messager); });
newThread.detach();
}
else
{
locker.unlock();
}
}
}
DWORD TCPConnectionV5::exchange(SOCKET messager)
{
int bytesSent = sendMessage(messager, msg);
if (bytesSent <= 0)
{
closesocket(messager);
return -1;
}
int bytesReceived = receiveMessage(messager);
if (bytesReceived <= 0)
{
closesocket(messager);
return -1;
}
}
I noticed that when the server connects with multiple clients, that there sometimes appear to be duplicate messages that send to some clients, which is accompanied by missing messages to another client application. I have mutex lock/unlock in place for sending/receiving messages, but what's causing these duplicate/missing messages? Is there some underlying issue I have to address regarding the threads?
I am trying to run this simple server client program's using winsock. Server is accepting the clients connection, but is unable to receive the data client sends. I am struggling to find the problem.
SERVER :
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define DEFAULT_PORT 18000
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
struct sockaddr_in server, client;
char *message, client_msg[2000];
int port, c, recv_size;
if (argc > 2)
{
std::cout << "usage : " << argv[1] << " <PORT>\n";
std::cout << "If no port is given then default port is used.\n";
std::cout << "DEFAULT PORT : 18000\n";
return 1;
}
if (argc == 2)
{
port = atoi(argv[2]);
}
else
{
port = DEFAULT_PORT;
}
std::cout << "Initializing Winsock...";
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
std::cout << "Failed. Error code" << WSAGetLastError();
return 1;
}
std::cout << "Initialized.\n\n";
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
std::cout << "Could not create Socket : " << WSAGetLastError() << "\n";
return 1;
}
std::cout << "Socket Created.\n";
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
std::cout << "Bind failed with error code : " << WSAGetLastError() << "\n";
}
std::cout << "Bind done.\n";
listen(s, 3);
std::cout << "Waiting for incoming connections...\n";
while (true)
{
c = sizeof(struct sockaddr_in);
new_socket = accept(s, (struct sockaddr*)&client, &c);
if (new_socket == INVALID_SOCKET)
{
closesocket(new_socket);
std::cout << "Accept failed with error code : " << WSAGetLastError() << "\n";
}
else
{
std::cout << "Connection accepted.\n";
if ((recv_size = recv(s, client_msg, 200, 0)) == SOCKET_ERROR)
{
closesocket(new_socket);
std::cout << "Receive Failed.\n\n";
}
else
{
if (strcmp(client_msg, "PASSWD"))
{
message = "HELLO!";
send(new_socket, message, strlen(message), 0);
}
else
{
message = "Authentication failed!";
send(new_socket, message, strlen(message), 0);
closesocket(new_socket);
}
}
}
}
closesocket(s);
WSACleanup();
return 0;
}
CLIENT:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define DEFAULT_SERVER "127.0.0.1"
#define DEFAULT_PORT 18000
#define PASSWORD "PASSWD"
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char *message, server_reply[2000], *server_addr;
int recv_size, port = DEFAULT_PORT;
if (argc > 4)
{
std::cout << "usage : " << argv[0] << " <Server IP> <Server Port> [DATA]\n\n";
std::cout << "If any argument is missing, default values will be used.\n";
std::cout << "Default Address : localhost (127.0.0.1)\nDefault Port : 18000\nDefault DATA: 'PASSWD'\n\n";
return 1;
}
else if (argc == 4)
{
server_addr = argv[1];
port = atoi(argv[2]);
message = argv[3];
}
else if (argc == 3)
{
server_addr = argv[1];
port = atoi(argv[2]);
message = PASSWORD;
}
else if (argc == 2)
{
server_addr = argv[1];
port = DEFAULT_PORT;
message = PASSWORD;
}
else
{
server_addr = DEFAULT_SERVER;
port = DEFAULT_PORT;
message = PASSWORD;
//server_addr = "127.0.0.1";
//port = 2222;
//message = "HELLO";
}
std::cout << "Initialising Winsock..\n";
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
std::cout << "Failed.. Error Code : " << WSAGetLastError() << "\n";
return 1;
}
std::cout << "Winsock Initialised.\n";
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
std::cout << "Could not create socket : " << WSAGetLastError() << "\n";
}
std::cout << "Socket Created.\n";
server.sin_addr.s_addr = inet_addr(server_addr);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (connect(s, (struct sockaddr*)&server, sizeof(server)) < 0)
{
std::cout << "Could not connect to " << server_addr << " on port " << port << ".\n";
WSACleanup();
return 1;
}
std::cout << "Connected to " << server_addr << " on port " << port << ".\n\n";
if (send(s, message, strlen(message), 0) < 0)
{
std::cout << "Sending Data failed.\n";
WSACleanup();
return 1;
}
std::cout << "Data send.\n\n";
//Sleep(500);
if ((recv_size = recv(s, server_reply, 20, 0)) == SOCKET_ERROR )
{
std::cout << "Receive Failed.\n\n";
}
else
{
server_reply[recv_size] = '\0';
std::cout << server_addr << " : " << server_reply << "\n";
}
//Sleep(5000);
closesocket(s);
WSACleanup();
return 0;
}
Any help would be appreciated. Thanks.
if ((recv_size = recv(s, client_msg, 200, 0)) == SOCKET_ERROR)
Change s to new_socket in your server side code.
I'm trying to get this code to work:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" )
#include <Windows.h>
using namespace std;
int port = 5012;
SOCKET listen_sock;
SOCKET client_sock;
char FR_recv_buf [1048576] = "";
char recv_buf [102400] = "";
int Receive();
int Listen();
//function to initialize winsock
bool InitializeWinsock()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(iResult != 0)
{
cout << "WSAStartup failed with error: " << iResult << endl;
return false;
}
else
{
cout << "WSAStartup successfully initialized." << endl;
return true;
}
}
int ForwardResponse()
{
if (send(client_sock, FR_recv_buf, sizeof(FR_recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Response: send() failed with error: " << WSAGetLastError() << endl;
closesocket(client_sock);
//WSACleanup();
return 0;
}
else
{
cout << "Forward Response: send() success.\n";
//go back to begginning again?
Receive();
//CreateThread(0,0,(LPTHREAD_START_ROUTINE)Receive, 0, 0 ,0);
}
}
//Function to parse hostname from http request
string ParseHostname(char * buf)
{
size_t pos;
//string to hold hostname substring
string hostname_t;
//copy request to string for easier parsing
string httpheader = buf;
pos = httpheader.find("Host: ");//find "Host: " line
hostname_t = httpheader.substr(pos + 6);//copy to substring, not including "Host: ", just the hostname
pos = hostname_t.find("\r\n");// find end of line
hostname_t.erase(pos);//erase the rest of the string which is unwanted
return hostname_t;
}
//Function to forward HTTP request from browser to webserver
int ForwardRequest()
{
int bytes_received;
SOCKADDR_IN Dest;
SOCKET frecv_sock;
hostent *Host;
//parse hostname from http request
string hostname = ParseHostname(recv_buf);
if((Host=gethostbyname(hostname.c_str()))==NULL)
{
DWORD dwError = WSAGetLastError();
if (dwError != 0)
{
if(dwError == WSAHOST_NOT_FOUND)
{
cout << "Host " << hostname.c_str() << " not found.\n";
WSACleanup();
return FALSE;
}
else if (dwError == WSANO_DATA)
{
cout << "No data record found.\n";;
WSACleanup();
return FALSE;
}
else
{
cout << "Function failed with error: " << dwError << endl;
WSACleanup();
return FALSE;
}
}
}
else
{
cout << "Successfully connected to host: " << hostname.c_str() << endl;
//privmsg(wsockdl.sock,sendbuf,curchan);
}
Dest.sin_family=AF_INET;
Dest.sin_port=htons(80);
memcpy(&Dest.sin_addr,Host->h_addr,Host->h_length);
// Create a SOCKET for connecting to server
if((frecv_sock = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
{
cout << "Forward Request: Error at socket(), error code: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return FALSE;
}
// Connect to server
if(connect( frecv_sock,(SOCKADDR*)&Dest,sizeof(Dest))==SOCKET_ERROR)
{
cout << "Forward Request: connect() failed, error code: " << WSAGetLastError() << endl;
closesocket( frecv_sock);
WSACleanup();
return FALSE;
}
//send intercepted request to server
if (send(frecv_sock, recv_buf, strlen(recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Request: send() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
else
{
cout << "Forward Request: send() success.\n";
}
//receive request from server
do{
bytes_received = recv(frecv_sock,FR_recv_buf,sizeof(FR_recv_buf),0);
if (bytes_received > 0){
strcat (FR_recv_buf, "\0");
cout << "Forward Request: recv() success. Bytes received: " << bytes_received << endl;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ForwardResponse, 0 ,0 ,0);
//ForwardResponse();
}
else if ( bytes_received == 0 ){
cout << "Forward Request: Connection closed\n";
closesocket(frecv_sock);
}
else if ( bytes_received == SOCKET_ERROR){
cout << "Forward Request: recv() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
}while (bytes_received > 0);
}
//Function to accept connection and receive data from browser
int Receive()
{
SOCKADDR_IN csin;
int csin_len = sizeof(csin);
int iResult;
//accept client connection
client_sock = accept(listen_sock , (LPSOCKADDR)&csin, &csin_len);//pauses here to wait for connection from client
if (client_sock == INVALID_SOCKET) {
cout << "accept failed with error: "<< WSAGetLastError() << endl;
closesocket(client_sock);
WSACleanup();
return 1;
}
else{
cout << "Client connection from IP: " << inet_ntoa(csin.sin_addr) << ":" << csin.sin_port << endl;
}
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0); //Start another thread to accept.
do {
iResult = recv(client_sock, recv_buf, sizeof(recv_buf), 0);
if (iResult == SOCKET_ERROR) {
closesocket(client_sock);
WSACleanup();
cout << "Receive: recv() failed with error: "<< WSAGetLastError() << endl;
}
else if (iResult > 0){
//null terminate receive buffer
//recv_buf[iResult] = '\0';
strcat(recv_buf, "\0");
cout <<"Receive: Bytes received: " << iResult << endl;
//forward HTTP request from browser to web server
cout << recv_buf << endl;
HANDLE pChildThread = CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)ForwardRequest, 0 , 0 ,0);
WaitForSingleObject(pChildThread,60000); //Wait for connection between proxy and remote server
CloseHandle(pChildThread);
}
else if ( iResult == 0 ){
cout << "Receive: Connection closed\n";
}
}while ( iResult > 0 );
return 0;
}
//Function which listens for incoming connections to the proxy
int Listen()
{
SOCKADDR_IN local;
memset(&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
//create socket for listening to
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
//bind function associates a local address with a socket.
if (bind(listen_sock, (LPSOCKADDR)&local, sizeof(local)) == 0)
{
if (listen(listen_sock, 10) == 0)
{
cout << "Listening on: " << port << endl;
}
else
{
cout << "Error listening on socket.\n";
}
}
else{
cout << "bind() failed with error: "<< WSAGetLastError() << endl;
}
//accept and start receiving data from broswer
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0);
return 0;
}
int CloseServer()
{
closesocket(client_sock);
WSACleanup();
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeWinsock();
Listen();
cin.get();
return 0;
}
But it seems like the connection ends too early, or the recv() or send() functions fail. Nothing is displayed on my browser except that it couldn't connect. Can anyone spot the problem?
One major problem is that you only have one client socket. Each thread you create share the same client socket so if two connections are made before the first one is done, the first socket will be over-written with the second connection. Remember that threads share all memory in the process, including things like global variables.
Edit: Since you are using C++, why don't you encapsulate variables and functions in a class? And instead of allocating memory for buffers statically like you do, create them on the heap with new.
Edit 2
Simple multi-threaded server:
class Connection
{
public:
Connection()
: buffer(0), buffer_size(0)
{ }
void run(SOCKET sock);
privat:
SOCKET input_socket; // Socket we read from
SOCKET output_socket; // Socket we write to
char *buffer; // Buffer we read data into, and write data from
size_t buffer_size; // Total size of buffer (allocated memory)
size_t read_size; // Number of bytes read
void connect();
void recv();
void send();
};
void Connection::run(SOCKET sock)
{
input_socket = sock;
if (buffer == 0)
{
// Allocate buffer
}
// Connect to the real server
connect();
for (;;)
{
try
{
recv();
send();
}
catch (exception &e)
{
std::cerr << "Error: " << e.what() << '\n';
break;
}
}
// Clean up
delete [] buffer;
closesocket(output_socket);
closesocket(input_socket);
}
void Connection::recv()
{
// Read data into the buffer, setting "read_size"
// Like: read_size = recv(input_socket, buffer_size, 0);
// Throw exception on error (includes connection closed)
// NOTE: If error is WSAEWOULDBLOCK, set read_size to 0, don't throw exception
}
void Connection::send()
{
if (read_size > 0)
{
// Send data from the buffer
// Like: send(output_socket, buffer, read_size, 0))
// Throw exception on error
}
}
void Connection::connect()
{
// Connect to the real server
// Set the output_socket member variable
}
DWORD client_thread(LPVOID param)
{
SOCKET socket = (SOCKET) param;
// Make socket nonblocking
int mode = 1;
ioctlsocket(socket, FIONBIO, &mode)
// Main thread stuff
Connection connection;
connection.run(socket);
}
int main()
{
// Create master socket, and other initialization
for (;;)
{
SOCKET client_socket = accept(...);
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE) client_thread,
(LPVOID) client_socket , 0 ,0);
}
// Clean up
}
Another major problem is that you are appending '\0' to the received buffer in the apparent expectation that send() will recognize it and stop sending from there, even though the size parameter to send() is sizeof(FR_recv_buf), which is what it will really respect. Another problem is that data items such as FR_recv_buf are instance variables instead of local variables, so you can't handle multuple concurrent connections.
I have a program that needs to constantly ping a device
However this ping function fails exactlly after 1020 tries
int ping(string target)
{
int s, i, cc, packlen, datalen = DEFDATALEN;
struct hostent *hp;
struct sockaddr_in to, from;
//struct protoent *proto;
struct ip *ip;
u_char *packet, outpack[MAXPACKET];
char hnamebuf[MAXHOSTNAMELEN];
string hostname;
struct icmp *icp;
int ret, fromlen, hlen;
fd_set rfds;
struct timeval tv;
int retval;
struct timeval start, end;
int /*start_t, */end_t;
bool cont = true;
to.sin_family = AF_INET;
// try to convert as dotted decimal address, else if that fails assume it's a hostname
to.sin_addr.s_addr = inet_addr(target.c_str());
if (to.sin_addr.s_addr != (u_int)-1)
hostname = target;
else
{
hp = gethostbyname(target.c_str());
if (!hp)
{
cerr << "unknown host "<< target << endl;
return -1;
}
to.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
hostname = hnamebuf;
}
packlen = datalen + MAXIPLEN + MAXICMPLEN;
if ( (packet = (u_char *)malloc((u_int)packlen)) == NULL)
{
cerr << "malloc error\n";
return -1;
}
/*
if ( (proto = getprotobyname("icmp")) == NULL)
{
cerr << "unknown protocol icmp" << endl;
return -1;
}
*/
if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
perror("socket"); /* probably not running as superuser */
return -1;
}
icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = 12345; /* seq and id must be reflected */
icp->icmp_id = getpid();
cc = datalen + ICMP_MINLEN;
icp->icmp_cksum = in_cksum((unsigned short *)icp,cc);
gettimeofday(&start, NULL);
i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
if (i < 0 || i != cc)
{
if (i < 0)
perror("sendto error");
cout << "wrote " << hostname << " " << cc << " chars, ret= " << i << endl;
}
// Watch stdin (fd 0) to see when it has input.
FD_ZERO(&rfds);
FD_SET(s, &rfds);
// Wait up to one seconds.
tv.tv_sec = 1;
tv.tv_usec = 0;
while(cont)
{
retval = select(s+1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select()");
return -1;
}
else if (retval)
{
fromlen = sizeof(sockaddr_in);
if ( (ret = recvfrom(s, (char *)packet, packlen, 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
{
perror("recvfrom error");
return -1;
}
// Check the IP header
ip = (struct ip *)((char*)packet);
hlen = sizeof( struct ip );
if (ret < (hlen + ICMP_MINLEN))
{
cerr << "packet too short (" << ret << " bytes) from " << hostname << endl;;
return -1;
}
// Now the ICMP part
icp = (struct icmp *)(packet + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY)
{
cout << "Recv: echo reply"<< endl;
if (icp->icmp_seq != 12345)
{
cout << "received sequence # " << icp->icmp_seq << endl;
continue;
}
if (icp->icmp_id != getpid())
{
cout << "received id " << icp->icmp_id << endl;
continue;
}
cont = false;
}
else
{
cout << "Recv: not an echo reply" << endl;
continue;
}
gettimeofday(&end, NULL);
end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
if(end_t < 1)
end_t = 1;
cout << "Elapsed time = " << end_t << " usec" << endl;
return end_t;
}
else
{
cout << "No data within one seconds.\n";
return 0;
}
}
return 0;
}
If i run the ping function twice it fails at exactly half 510. And the pattern is exact. Here is the output after the 1020 mark
socket: Too many open files
ping returned -1
Im pretty bad at network programming but i dont even know where to begin for the above code.
Am i missing a close somewhere?
The ping function is taken from: http://www.linuxforums.org/forum/networking/60389-implementing-ping-c.html
Edit: Running Ubuntu 10.10, same issue on Fedora 13
Thanks
Yes, you need to close the socket with close(s); before exiting the function.
When allocating resources you need to make sure to free them.
As unwind pointed out, you have to close sockets.
But you also need to free the allocated memory (malloc, line 40-ish).
You should consider using memcpy instead of bcopy.
Agree with "unwind".
Note that you run a function, not a program. Hence your process is still alive, and all the memory/resource leaks are not automatically freed.
As a general rule, if you see in the code a call to a socket function without the corresponding closesocket - this must always scratch your eyes!