I am working on a application which works by received commands (API calls) over a socket connection. The application has two socket server with two different port numbers. As said the application is acting on the received commands (string). What is the best way to setup the socket server(s)? The socket server object is been build in a class file and contains two threads (listen for connections, handling the new connected client). The question is, what will be the best way to use the received commands/data so that the application will respond to it. Should I buildin a buffer (vector of string) to store the received data, read this buffer in the main loop of the application and after the reading clear the vector? Or is there a better/ other way?
The code of the socket server class is:
void SocketServer::Startup()
{
WSADATA wsa;
WSAStartup(0x0202, &wsa);
this->WorkerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
this->EndPnt.sin_addr.s_addr = INADDR_ANY;
this->EndPnt.sin_family = AF_INET;
this->EndPnt.sin_port = htons(this->m_port);
this->Enabled = true;
this->ID = 0;
bind(this->WorkerSocket, (SOCKADDR*)&this->EndPnt, sizeof(this->EndPnt));
printf("[SocketServer]Bound on %d..\n", this->m_port);
listen(this->WorkerSocket, this->Backlog);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ServerMainThread, this, NULL, NULL);
}
void SocketServer::WaitForConnections(SocketServer * Ser)
{
while(Ser->Enabled)
{
SOCKET accptsock = accept(Ser->WorkerSocket, NULL, NULL);
printf("[SocketServer]Client connected.\n");
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ServerDataThread, (LPVOID)accptsock, NULL, NULL);
}
}
void SocketServer::WaitForData(LPVOID lpParam)
{
SOCKET sock = (SOCKET)lpParam;
char *message = "ECHO Daemon v1.0 \r\n";
send(sock, message, strlen(message), 0);
int res;
char buffer[255];
while(true)
{
res = recv(sock, buffer, sizeof(buffer), 0);
if( res == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if(error_code == WSAECONNRESET)
{
//Somebody disconnected , get his details and print
cout << "[SocketServer]Client disconnected" << endl;
//Close the socket and mark as 0 in list for reuse
closesocket(sock);
ExitThread(0);
}
else
{
closesocket(sock);
ExitThread(0);
}
}
if(res == 0)
{
closesocket(sock);
ExitThread(0);
}
else
{
cout << buffer << endl;
// insert data to vector here
send(sock , buffer , sizeof(buffer) , 0 );
}
}
}
DWORD WINAPI SocketServer::ServerMainThread(LPVOID lParam)
{
((SocketServer*)lParam)->WaitForConnections((SocketServer*)lParam);
return 0;
}
DWORD WINAPI SocketServer::ServerDataThread(LPVOID lParam)
{
((SocketServer*)lParam)->WaitForData((LPVOID)lParam);
return 0;
}
The vector it needs to push the data to is called "Buffer", "Buffer.push_back(buffer)";
Related
I'm writing a server in C++ on windows. On connection, the server creates two threads to handle the request - one constantly reading the input from the socket and the second constantly writes output to it. I'm experiencing problems with it because when there's no input from the client but output to send to it thread #1 is blocking on recv() making thread two block on send() and not write it's data.
Is there a way to send() to a socket although it is already in blocking recv()?
Thanks
EDIT:
I took out the relevant code and reproduced the issue. if I comment out the AfxThreadCall to the readThread, the data is being sent. otherwise it isn't. the client is a simple client that prints what it recieves.
SOCKET m_sockIOSrv = NULL;
SOCKET m_sockIO = NULL;
UINT readThread(LPVOID args)
{
WSABUF DataBuf;
DWORD RecvBytes;
DWORD Flags = 0 ;
char buf[4096];
DataBuf.len = 4096;
DataBuf.buf = buf;
while (true)
{
int ret = WSARecv(m_sockIO, &DataBuf, 1, &RecvBytes, &Flags, NULL, NULL); // Read some data...
if (ret == SOCKET_ERROR)
{
printf("ERROR: WSARecv: %d", WSAGetLastError());
return 1;
}
printf("jobleader - got %d from recv\n", RecvBytes);
}
return 0;
}
UINT writeThread(LPVOID args)
{
WSABUF DataBuf;
DWORD SendBytes;
DWORD Flags;
char buf[] = { 'a', 'a', 'a' };
DataBuf.len = 3;
DataBuf.buf = buf;
while (true)
{
DWORD dwWritten;
WSASend(m_sockIO, &DataBuf, 1, &dwWritten, 0, NULL, NULL);
}
return 0;
}
SOCKET ServerSocket(unsigned int & port) {
// Our server socket
SOCKET s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (s == INVALID_SOCKET)
return s;
SOCKADDR sa;
sa.sa_family = AF_INET;
memset(sa.sa_data, 0, sizeof(sa.sa_data));
if (bind(s, &sa, sizeof(sa))) {
closesocket(s);
return INVALID_SOCKET;
}
struct sockaddr_in sa_in;
int sz = sizeof(sa_in);
if (getsockname(s, (struct sockaddr *)&sa_in, &sz)) {
closesocket(s);
return INVALID_SOCKET;
}
if (listen(s, 50)) {
closesocket(s);
return INVALID_SOCKET;
}
port = ntohs(sa_in.sin_port);
return s;
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int ioPort = 0;
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(wVersionRequested, &wsaData))
{
if (!AfxSocketInit())
{
printf("ERROR: Unable to initialize WinSock DLL");
exit(2);
}
}
m_sockIOSrv = ServerSocket(ioPort);
if (m_sockIOSrv == INVALID_SOCKET) {
int lastError = GetLastError();
printf("ERROR: StartIOSockets Failed to start socket %d.\n",lastError);
return 1;
}
printf("Listening on %d\n", ioPort);
m_sockIO = accept(m_sockIOSrv, NULL, NULL);
AfxBeginThread(&readThread, (LPVOID)NULL);
AfxBeginThread(&writeThread, (LPVOID)NULL);
getchar();
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Well heres the thing : i want to make a remote cmd so whenever im at work i can download files from my home computer , for somereason it doesnt respond the way i want to , when i send the dir command it doesnt even execute the if statement .
Please forgive me if this is obvious Im new to those stuff.
Notes:
Server connects and client prints out the sent buffer.
those are different programs v
Server.cpp
#include "FirstTouch.h"
#pragma comment(lib,"ws2_32")
void SendCommands()
{
while (1)
{
char SendBuffer[1500];
cin >> SendBuffer;
send(sConn, SendBuffer, 1500, 0);
if (SendBuffer == "dir")
{
printf("system_dir initiated\n");
Sleep(200);
char File[1500];
recv(sConn, File, strlen(File), 0);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 9);
cout << File << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
delete File;
}
}
}
int main()
{
ConnectToServer();
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
printf("connected");
system("cls");
SendCommands();
return 0;
}
Client.cpp
#include <winsock.h>
#include <iostream>
#pragma comment(lib,"ws2_32")
SOCKET s; //Socket handle
//CONNECTTOHOST – Connects to a remote host
bool ConnectToHost(int PortNo, char* IPAddress)
{
//Start up Winsock…
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
//Did something happen?
if (error)
return false;
//Did we get the right Winsock version?
if(wsadata.wVersion != 0x0202)
{
WSACleanup(); //Clean up Winsock
return false;
}
//Fill out the information needed to initialize a socket…
SOCKADDR_IN target; //Socket address information
target.sin_family = AF_INET; // address family Internet
target.sin_port = htons(PortNo); //Port to connect on
target.sin_addr.s_addr = inet_addr(IPAddress); //Target IP
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
if (s == INVALID_SOCKET)
{
return false; //Couldn't create the socket
}
//Try connecting...
if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
return false; //Couldn't connect
}
else
return true; //Success
}
//CLOSECONNECTION – shuts down the socket and closes any connection on it
void CloseConnection()
{
//Close the socket if it exists
if (s)
closesocket(s);
WSACleanup(); //Clean up Winsock
}
int main()
{
bool Conn = false;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
printf("Trying to make a reliable connection to server...");
while (!Conn)
{
Conn = ConnectToHost(444, "127.0.0.1");
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
system("cls");
printf("Connected say hi!\n");
while (1)
{
char RecvBuffer[1500];
recv(s, RecvBuffer, 1500, 0);
printf(RecvBuffer);
std::cout << std::endl;
if (RecvBuffer == "dir")
{
printf("Executing...\n");
Sleep(100);
system("dir >> temp.txt");
HANDLE hFile = CreateFile("temp.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
LPVOID FileContent = nullptr;
LPDWORD NumOfBytes = nullptr;
ReadFile(hFile, FileContent, 1500, NumOfBytes, NULL);
CloseHandle(hFile);
delete[] NumOfBytes;
send(s, (char*)FileContent, 1500, 0);
delete FileContent;
}
}
return 0;
}
recv() isn't guaranteed to fill the buffer. You have to loop.
I have a TCP application written in C++, where a client and a server exchange data. I've istantiated a socket, believing that it would have been blocking by default; on the contrary, after server waits for a client, I have that client calls the recv function without waiting for data. This is the code in which I inizialize the socket fr the client.
int TCPreceiver::initialize(char* address, int port)
{
sock = socket (AF_INET, SOCK_STREAM, 0);
cout << "Socket: " << sock << endl;
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons (port);
target.sin_addr.s_addr = inet_addr(address);
int fails=0;
while (connect(sock, (sockaddr*) &target, sizeof(target)) == -1)
{
fails++;
if (fails==10)
{
close(sock);
cout << "Error with connection to the server, try again"<< endl;
exit(-1);
}
}
cout << "Client connected (control channel)" << endl;
unsigned char text[10]; //Request message
//fill text[]
if(send(sock, (char*)text, 10, 0)==-1)
{
printf("send() failed with error code : %d" , -1);
exit(EXIT_FAILURE);
}
return 0;
}
I've tried adding this code:
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(0);
}
opts = (opts & (~O_NONBLOCK));
if (fcntl(sock,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
exit(0);
}
but it still doesn't work, and if I call the recv(), the application doesn't block (and recv() always returns 0). Here is the function where I call the recv():
void TCPreceiver::receive(char* text, int& dim)
{
int ret;
ret = recv(sock, text, dim, 0);
dim=ret;
if(ret == -1){
printf("recv() failed with error (%d)\n", ret);
//system("PAUSE");
exit(1);
}
}
Where am I wrong?
recv() returning zero indicates either (1) you passed a zero length, which is just a programming error which I won't discuss further here, or (2) end of stream. The peer has close the connection. This isn't a non-blocking situation, this is the end of the connection. You must close the socket and stop using it. It will never return anything. It zero ever again.
See the man pages.
I've been working on a small network based chess application. I managed to create a server that can handle multiple connections, however I don't know how to send data from one client to another.
Here is the partial Server implementation
//function to handle our Socket on its own thread.
//param- SOCKET* that is connected to a client
DWORD WINAPI HandleSocket(void* param)
{
string test;
SOCKET s = (SOCKET)param;
User temp;
temp._socket = (SOCKET)param;
temp._inGame = false;
userlist.add(&temp);
std::cout<<"connection"<<endl;
int bytesread = 0;
int byteswrite=0;
while(true)
{
//receive
bytesread = recv(s, reinterpret_cast<char*>(test.c_str()), BUF_LEN, 0);
//error check
if(bytesread == SOCKET_ERROR)
{
std::cout << WSAGetLastError();
//shutdown and close on error
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
//check for socket being closed by the client
if(bytesread == 0)
{
//shutdown our socket, it closed
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
byteswrite = send(s, "test" , 255 , 0);
if(byteswrite == SOCKET_ERROR)
{
std::cout << WSAGetLastError();
//shutdown and close on error
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
test.clear();
}
}
Maybe you should start a thread for a new game when both players of the game are connected to the server. In that case you can deliver both sockets to the thread by the following way:
DWORD WINAPI HandleGame(void* param)
{
GameState* game = (GameState*)param;
SOCKET s1 = game->getSocketOfPlayer(1);
SOCKET s2 = game->getSocketOfPlayer(2);
...
// TODO: Forward game messages between clients (players).
...
delete game;
return 0;
}
Alternative solutions: Implement the server program in sigle thread.
In both cases you propably need select() function for waiting messages from several players simultaneously.
Now I'm new to the WINSOCKs, and not super fluent in C++, so bear with me. I've written a NetworkServer and NetworkClient class, mostly based off of the MSDN tutorials. The client will be sending the server a char array of size 256, containing the state of each standard keyboard button (0 means the key is not being pressed, 1 means it is being pressed).
When running the code, I first start the server, and then the client. They connect to each other fine. The client is then called to send the keyboard buffer. The buffer is sent, but the server hangs after:
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
The "keys" variable in each class is a char keys[256] to hold each of the key states.
Below is the loop that occurs once a NetworkServer has been started:
char buffer[256];
int receiveResult, sendResult;
// Receive from the client
do
{
receiveResult = recv(theClient, buffer, sizeof(buffer), 0);
if (receiveResult > 0 )
{
sendResult = send(theClient, buffer, receiveResult, 0);
if (sendResult == SOCKET_ERROR)
{
sendResult = WSAGetLastError();
JBS::reportSocketError(nret, "server send()");
closesocket(theClient);
WSACleanup();
return;
}
else
{
memcpy(keys, buffer, sizeof(keys));
}
}
else if (receiveResult == 0)
cout << "Server closing." << endl;
else
{
receiveResult = WSAGetLastError();
JBS::reportSocketError(nret, "server receive()");
closesocket(theClient);
WSACleanup();
return;
}
} while (receiveResult > 0);
And here is the NetworkClient send method:
char buffer[256];
memcpy(buffer, keys, sizeof(buffer));
nret = send(theSocket, buffer, sizeof(buffer),0);
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client send()");
closesocket(theSocket);
WSACleanup();
}
do
{
char buff[256];
nret = recv(theSocket, buff, sizeof(buff), 0);
if (nret > 0)
{
memcpy(keys, buff, sizeof(keys));
}
else if (nret == 0)
cout << "Server connection closed" << endl;
else
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client receive()");
closesocket(theSocket);
WSACleanup();
}
} while (nret > 0);
As I said, the connection is being established between client and server, but the receiving part of the process doesn't seem to be working. Any help would be appreciated.
NetworkClient's start method:
sockVersion = MAKEWORD(1, 1);
// Initialize Winsock as before
WSAStartup(sockVersion, &wsaData);
// Store information about the server
LPHOSTENT hostEntry;
hostEntry = gethostbyname(serverAddress); // Specifying the server by its name;
if (!hostEntry) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client gethostbyname()"); // Report the error as before
closesocket(theSocket);
WSACleanup();
}
// Create the socket
theSocket = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (theSocket == INVALID_SOCKET) {
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client socket()");
closesocket(theSocket);
WSACleanup();
}
// Fill a SOCKADDR_IN struct with address information
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
serverInfo.sin_port = htons(PORT); // Change to network-byte order and
// insert into port field
// Connect to the server
nret = connect(theSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));
if (nret == SOCKET_ERROR)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client connect()");
closesocket(theSocket);
WSACleanup();
}
// Successfully connected!
started = true;
in the client code, you wrote:
char buff[256];
nret = recv(theSocket, buff, (int)strlen(buff), 0);
this means that you want to receive data into a buffer which length is strlen(buff). unfortunately, strlen() returns the length of the string inside the buffer, that is the length of data before any NUL character inside the buffer. your compiler was smart enough to initialize buff with NUL characters, thus strlen(buf) returns 0, which means that you want to receive 0 bytes of data. thus, recv() does not receive anything.
what you meant is:
nret = recv(theSocket, buff, sizeof(buff), 0);
(if you tried compiling your program using the Release build, it would have crashed happily, because buff would then not be initialized, and strlen() would have returned a pretty random result which would have caused the program to access an invalid memory address...)
i should add that the way you declare your buffer is unfortunate: you have an array of booleans (value 1 or 0 depending of the state of keys). a boolean is not a char. a strict declaration should be bool buff[256]...
Problem ended up being how I was assigning the values in the keyBuffer. I was doing
void key(unsigned char key, int x, int y)
{
player.keyDown[key] = 1;
}
Instead of
void key(unsigned char key, int x, int y)
{
player.keyDown[key] = '1';
}