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';
}
Related
Please guide me why is blocking function recv() not waiting for message from client. Instead it is returning value -1. Please guide me how to resolve this issue.
Server code (partial):
(call to getaddrinfo) // struct addrinfo hints, *res
int sfd = socket(res->ai_family, res->ai_socktype,res->ai_protocol);
if(sfd == -1)
{
printf("Socket creation failed .....");
exit(-3);
}
fcntl(sfd, F_SETFL, ~O_NONBLOCK);
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
{
herror("setsockopt(SO_REUSEADDR) failed");
}
bind(sfd,res->ai_addr, res->ai_addrlen);
if(listen(sfd, BACKLOG)!=0)
{
printf("Listen Error");
exit(-4);
}
printf("\n\nListening on port: %s\n\n", argv[1]);
struct sockaddr_storage clientAddr;
socklen_t addrSize = sizeof(clientAddr);
int connFD = accept(sfd,(struct sockaddr*)&clientAddr, &addrSize); // connection successful
char buffer[10] = "Hello!";
write(connFD, buffer, sizeof(buffer)); // message sent to client
buffer[0] = '\0';
int bytesReceived;
if((bytesReceived = recv(sfd, buffer, sizeof(buffer), 0)) == -1) // Problem starts here
{
fprintf(stderr,"Could not retrieve message from client.");
exit(-5);
}
the problem is that you are calling recv on wrong socket (sfd) should be (connFD)
fix:
if((bytesReceived = recv(connFD, buffer, sizeof(buffer), 0)) == -1)
I got rid of the error, now I seem to be stuck on something else.
I have separate Winsock client and server programs on Code::Blocks. I'm trying to send a message from the client to the server, but the server program seems to freeze before the accept() function, doing nothing beyond the "Listening for incoming connections." output. The message in the client buffer never shows up in the server console.
It definitely looks like there's something going on with the accept function in the server program. That seems to be where the server program freezes. I tried to type a random cout line after that and there was no output for it.
The client seems to freeze, too, after "Message Sent." But then after a few minutes I get "recv failed" then "Reply Received" and then a line of what seems like emoticons. I think I have the image linked below.
enter image description here
Here's my client code:
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
WSADATA wsaData;
SOCKET sock;
sockaddr_in server;
char *buffer, server_reply[2000];
int recv_size;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
} else {
printf("WSAStartup successful!: %d\n", iResult);
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET){
printf("Socket not created.\n");
} else {
printf("Socket created.\n");
}
server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(80);
if(connect(sock, (SOCKADDR *)&server, sizeof(server)) != 0){
printf("Connect Error : %d" , WSAGetLastError());
} else {
printf("Connected\n");
};
buffer = "Hello there!";
send(sock, buffer, sizeof(buffer), 0);
printf("Message Sent.\n");
if((recv_size = recv(sock , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
closesocket(sock);
WSACleanup();
return 0;
}
Here's my server code:
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
WSADATA wsaData;
SOCKET server1, client;
sockaddr_in serverAddr, clientAddr;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
} else {
printf("WSAStartup successful!: %d\n", iResult);
}
server1 = socket(AF_INET, SOCK_STREAM, 0);
if (server1 == INVALID_SOCKET){
printf("Socket not created.\n");
} else {
printf("Socket created.\n");
}
serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
if(bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){
printf("Bind failed. : %d" , WSAGetLastError());
} else {
printf("Bind successful.\n");
}
if(listen(server1, SOMAXCONN) != 0){
printf("Server not listening. : %d" , WSAGetLastError());
} else {
cout << "Listening for incoming connections..." << endl;
}
char buffer[1024];
int clientAddrSize = sizeof(clientAddr);
if((client = accept(server1, (SOCKADDR *)&clientAddr, &clientAddrSize)) == INVALID_SOCKET)
{
printf("Connect Error : %d" , WSAGetLastError());
} else {
cout << "Client connected!" << endl;
recv(client, buffer, sizeof(buffer), 0);
cout << "Client says: " << buffer << endl;
memset(buffer, 0, sizeof(buffer));
closesocket(client);
closesocket(server1);
cout << "Client disconnected." << endl;
}
WSACleanup();
return 0;
}
I'm trying to build a Winsock server program to use with my client program using C++ in CodeBlocks. However, the accept function returns error code 10022, which from what I've read means invalid argument. I don't see how any of my arguments in the accept function are invalid. Thanks for any help!
int main()
{
WSADATA wsaData;
SOCKET server1, client;
sockaddr_in serverAddr, clientAddr;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
} else {
printf("WSAStartup successful!: %d\n", iResult);
}
server1 = socket(AF_INET, SOCK_STREAM, 0);
if (server1 == INVALID_SOCKET){
printf("Socket not created.\n");
} else {
printf("Socket created.\n");
}
serverAddr.sin_addr.S_un.S_addr = inet_addr(INADDR_ANY);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888);
bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr));
listen(server1, SOMAXCONN);
cout << "Listening for incoming connections..." << endl;
char *buffer;
int clientAddrSize = sizeof(clientAddr);
if((client = accept(server1, (SOCKADDR *)&clientAddr, &clientAddrSize)) == INVALID_SOCKET)
{
printf("Connect Error : %d" , WSAGetLastError());
} else {
cout << "Client connected!" << endl;
recv(client, buffer, sizeof(buffer), 0);
cout << "Client says: " << buffer << endl;
memset(buffer, 0, sizeof(buffer));
closesocket(client);
closesocket(server1);
cout << "Client disconnected." << endl;
}
WSACleanup();
return 0;
}
10022 is WSAEINVAL. Per the accept() documentation:
WSAEINVAL
The listen function was not invoked prior to accept.
The Windows Socket Error Codes documentation also says:
WSAEINVAL
10022
Invalid argument.
Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening.
OK, so lets look at your listen() call:
listen(server1, SOMAXCONN);
Nothing out of the ordinary there, assuming server1 is a valid socket (which you do check for, but you don't stop your program if socket() failed).
You are not checking for any listen() errors. Per the listen() documentation, one of the possible errors is:
WSAEINVAL
The socket has not been bound with bind.
OK, so lets look at your bind() call next:
bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr));
Again, you are not checking for any bind() errors. Per the bind() documentation, one of the possible errors is:
WSAEADDRNOTAVAIL
The requested address is not valid in its context.
This error is returned if the specified address pointed to by the name parameter is not a valid local IP address on this computer.
Which you are likely to get, because you are not populating serverAddr correctly, specifically on this line:
serverAddr.sin_addr.S_un.S_addr = inet_addr(INADDR_ANY);
INADDR_ANYis defined as 0, so you are setting the S_addr field to the result of inet_addr(0), which is not valid so INADDR_NONE (0xFFFFFFFF) is returned, which again, you are not checking for. The correct assignment is to use INADDR_ANY as-is instead:
serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
So, to wrap up, your error handling is inadequate, allowing errors to accumulate until you finally decide to do for errors all the way on accept(), which is way too late. You need to check EVERY function result for failure along the way, and STOP when you do encounter an error.
inet_addr takes const char* which represents IPv4 address in numbers and dots notation. You are passing INADDR_ANY to this function, it compiles but doesn't work as expected because INADDR_ANY equals 0, so inet_addr is called with null pointer. You should check the return code of this function, -1 indicates the error. And I assume you got it.
If you want to bind any local address you should use INADDR_ANY with htonl:
serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
This
char *buffer;
recv(client, buffer, sizeof(buffer), 0);
leads to undefined behaviour. buffer is uninitialized. This call of recv wants to read 4/8 bytes - sizeof(buffer), and write into uninitialized buffer pointer. You need to create a buffer with some initial size, for example by calling malloc/calloc:
char * buffer = malloc(10);
recv(client,buffer,10,0);
// free buffer after data was read
Just remove this line from your code:
using namespace std;
And every thing will work fine.
This error is caused because std package have a similar bind function so when you call bind it calls std::bind instead of the bind for the socket.
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)";
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 wanted to create an asynchronous/non-blocking udp client server application where the client and server were supposed to chat away with each other without waiting for each other's turns.
I came to know that this could be done by select()...
here is my Server(Mentioning only the communication part):
fd_set readfds,writefds;
while(1){
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(sd,&readfds);
FD_SET(sd,&writefds);
int rv = select(n, &readfds, NULL, NULL, NULL);
if(rv==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
if(rv==0)
{
printf("Timeout occurred\n");
}
if (FD_ISSET(sd, &readfds))
{
int client_length = (int)sizeof(struct sockaddr_in);
memset(&buffer,0,sizeof(buffer));
int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0) {
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
}
printf("\nClient says: %s",buffer);
printf("\nWrite :");
fgets(buffer,SIZE,stdin);
if(FD_ISSET(sd,&writefds)) {
int client_length = (int)sizeof(struct sockaddr_in);
if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0) {
printf("Error sending the file! \n");
printf("%d\n",WSAGetLastError());
exit(1);
}
}
}
closesocket(sd);
WSACleanup();
return 0;
}
and this is my client:
fd_set readfds,writefds;
while(1)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(cs,&readfds);
FD_SET(cs,&writefds);
int rv=select(n,&readfds,&writefds,NULL,NULL);
if(rv==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
if(rv==0)
{
printf("Timeout occurred\n");
}
printf("\nWrite ");
fgets(send_buffer,SIZE,stdin);
if(FD_ISSET(cs,&writefds))
{
int server_length = sizeof(struct sockaddr_in);
FD_CLR(cs,&writefds);
if (sendto(cs, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&server, server_length) == -1)
{
fprintf(stderr, "Error transmitting data.\n");
closesocket(cs);
WSACleanup();
exit(0);
}
}
char file_buffer[SIZE];
//Reply reception from the server:"Ready to receive file"
int data2=0;
if (FD_ISSET(cs, &readfds))
{
FD_CLR(cs,&readfds);
int server_length = sizeof(struct sockaddr_in);
data2=recvfrom(cs,file_buffer,strlen(file_buffer)-1,0,(struct sockaddr *)&server,&server_length);
//file_buffer[data2]='\0';
if(data2<0)
{
printf("Server is not on:(\n");
exit(0);
}
}
//printf("%d",data2);
printf("\nServer says:");
for(int i=0;i<data2;i++)
{
putchar(file_buffer[i]);
}
}
return 0;
}
At first on the server side I wrote:int rv = select(n, &readfds, &writefds, NULL, NULL);
but that led to the printing of an entire empty array on the server console when the server initialised in addition to the fact that communication between the server and client was not proper.
removing "&writefds" did remove the redundant data but the improper communication issue still persists...
So I would be really thankful if somebody helped me out...
I see a couple of problems with your code.
First of all, if you want to wait for input from both the socket and the terminal, you should put both of those fds into the readfds set:
FD_SET(cs, &readfds);
FD_SET(stdin, &readfds);
Since you're not doing any writing, you shouldn't be using writefds.
Next, you should make sure that you're only trying to read from the terminal if it has input ready. So, you should be doing something like:
if (FD_ISSET(stdin, &readfds)) {
// Read in from terminal...
}
You're currently trying to read each time, no matter what happens.
Last, you're measuring the size of your file_buffer incorrectly when you make your recvfrom call. strlen only works once you've already put data into it. You should be using sizeof(file_buffer).