Blocking connection between server-client using socket communication - c++

I am having some strange problem with my client-server connection using UDP and SFML and I am slowly running out of ideas what might be wrong, so maybe someone will be able to help me.
Currently I can connect client to server and send message from server to client. When I kill the client application and restart it again (on this same machine), provide this same connection parameters of server, nothing happens. It appears like if there is no connection established. Client is just waiting for message form server, while server is constantly sending messages at the same time.
My server side looks like that:
std::shared_ptr<sf::UdpSocket> startUdpServer()
{
std::cout << "Local address: ";
std::cout << sf::IpAddress::getLocalAddress().toString() << std::endl;
std::cout << "Public address: ";
std::cout << sf::IpAddress::getPublicAddress().toString() << std::endl;
std::shared_ptr<sf::UdpSocket> socket(new sf::UdpSocket());
if(socket->bind(sf::Socket::AnyPort) != sf::Socket::Done)
return nullptr;
std::cout << "Server is listening to port " << socket->getLocalPort() << ", waiting for a message... " << std::endl;
return socket;
}
std::pair<sf::IpAddress, unsigned short> runUdpServer(std::shared_ptr<sf::UdpSocket> socket)
{
// Wait for a message
char in[128];
std::size_t received;
sf::IpAddress sender;
unsigned short senderPort;
if (socket->receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
{
std::cout << "Connection error" << std::endl;
return std::make_pair(sender, senderPort);
}
std::cout << "Message received from client " << sender << ": \"" << in << "\"" << std::endl;
return std::make_pair(sender, senderPort);
}
void sendUdpMessage(std::shared_ptr<sf::UdpSocket> socket, std::pair<sf::IpAddress, unsigned short> config,
std::string message)
{
const char* out = message.c_str();
if (socket->send(out, sizeof(char) * message.length(), config.first, config.second) != sf::Socket::Done)
{
std::cout << "Message not send" << std::endl;
return;
}
}
void sendMessages(std::shared_ptr<sf::UdpSocket> socket, std::pair<sf::IpAddress, unsigned short> config)
{
if(config.first != sf::IpAddress::None)
{
while(true)
sendUdpMessage(socket,config,"Test msg");
}
else
std::cout << "Message sending error" << std::endl;
}
auto socket = startUdpServer();
auto config = runUdpServer(socket);
std::thread messages_thread(sendMessages,socket,config);
and my client:
std::shared_ptr<sf::UdpSocket> startUdpClient()
{
sf::IpAddress server;
do
{
std::cout << "Type the address or name of the server to connect to: ";
std::cin >> server;
}
while (server == sf::IpAddress::None);
unsigned short port;
std::cout << "Type the port number: ";
std::cin >> port;
std::shared_ptr<sf::UdpSocket> socket(new sf::UdpSocket());
sf::Packet packet;
const char out[] = "Hi, I'm a client";
if (socket->send(out, sizeof(out), server, port) != sf::Socket::Done)
return nullptr;
return socket;
}
void runUdpClient(std::shared_ptr<sf::UdpSocket> socket)
{
char in[256];
std::size_t received;
sf::IpAddress sender;
unsigned short senderPort;
if (socket->receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
return;
std::cout << "Message received: \"" << in << "\"" << std::endl;
}
auto socketUDP = startUdpClient();
std::thread messagesThread(receiveMessages,socketUDP);
void receiveMessages(std::shared_ptr<sf::UdpSocket> socket)
{
while(true)
runUdpClient(socket);
}

With networking there are 2 very important key notes to remember with UDP and TCP.
TCP - is connection based, this means everytime it attempts to send it a message it needs to have someone on the other end.
UDP - is connectionless based, this means he will send information to where ever you want him to. He can send and receive information, but in order to receive data he needs to be binded to a port. So in your server you are binding him to the same port everytime.
In your client you are giving him a port to send information to, not binding him to a specific port. Whenever you shut down your client he should release the port, and whenever you restart the client he should bind to the same port, if you want him to be able to receive data from your server. If you don't essentially whats going on is the data gets to the IP and port it was sent to, but there is no application associated with that port so the packet is lost.

In order to communicate between two parties via UDP, each side needs a unique (address, port) pair. Typically the server binds its socket to a fixed/well-known port, and the client port varies by client -- hence allowing multiple clients to communicate with the same server, each on their own port.
If your client, as here, doesn't explicitly bind its socket to a port, the operating system will dynamically allocate a "random" unused port to it and automatically bind it on the first use of the port for sending data. As long as that client continues to use the same socket, the port number is fixed.
However, when you restart the client side, it gets a new socket and on its first send using the new socket, the OS binds the socket to a new port. Your server however, is assuming that the client port number is still the number that it received from the first client.
Because of the way this works, for UDP servers, the usual pattern is that every message stands alone. The server makes note of the client's address and port number every time it receives a message and then responds back to that address/port. The server typically doesn't assume that any two consecutive messages will come from the same client as there is no way for it to know when any given client has disappeared.
(You can build your own more durable "connection" notion atop UDP -- as NFS traditionally did, for example -- but that is a significant amount of work that requires due care in designing your protocol. And it works within this same fundamental model described above.)
It is also possible for your client to always explicitly bind to a port you select. However, that would limit you to running one instance of the client on any one machine (well, on any one network address really).

Related

C++ recv not receiving anything when NIC received data

I am writing a C++ server program and a Qt client program. The problem is, recv() keeps waiting forever when tcpdump clearly shows a tcp packet from client is delivered to my network interface.
Server program is ran on Centos 7.7 and compiled with g++ 4.8.5
while (true) {
sockaddr_in client_addr{0};
socklen_t client_len = sizeof(sockaddr_in);
newsockfd = accept(sockfd, (sockaddr*)&client_addr, &client_len);
cout << "New connection from " << inet_ntoa(client_addr.sin_addr) << endl;
long bytes;
char buf[1000];
while (true) {
bytes = recv(newsockfd, buf, 1000, 0);
if (bytes < 1) {
if (bytes < 0) { cout << "Error: " << errno << ", " << strerror(errno) << endl; }
break;
}
ProcessRequest(buf, bytes);
}
close(newsockfd);
cout << "Host " << inet_ntoa(client_addr.sin_addr) << " disconnected..." << endl;
}
Client program is ran on Windows and compiled with msvc 2017 and Qt:
QTcpSocket* loginClient = new QTcpSocket(this);
loginClient->connectToHost(ipAddr, Port);
if (!loginClient->waitForConnected(30000)) { return; }
char data[100] = "12345678";
int sendLen = loginClient->write(data, 9);
if (sendLen == -1) { return; }
The server is able to detect connection from client, so ip and port issues are out of the way. Furthermore, the server is not able to detect disconnection from this Qt client properly. Disconnection detection is usually postponed by numerous minutes or indefinitely.
An interesting thing is, I wrote another client program ran on another Centos, with which the server worked Perfectly. So I assume the server program is fine?
Thanks for any help.
Found the error. Turned out that Client side had made three connections to the server among which only one was connected and two in queue. The packet was coming into the server not from the connected socket. That is why the opened file descriptor doesn't read anything from NIC.

Connection To Poco Websocket Server gets Disconnected even when the server side is still listening

Update: I can run the server and client perfect locally when they are on the same host. The below scenario is when they are on separate machines(more specifically one is running on ARM64 Petalinux and other on Ubuntu). Perhaps I need to set some options on server side etc
I have a poco websocket server written over the standard sample provided by Poco and a javascript client. While trying to openwebsocket it will get connected in first go sometimes after trying 2-3 times and so on. Now once connected, it might send the message or just gets disconnected on the client side. While on the server side there is no error and I am pretty sure its still open because when i try to open another connection from the client side it will get connected on different client port.
Now the interesting thing is I wrote a Poco websocket client and sending/receiving message continuously without delay in a loop, the client remains active for sometime and then both server and client says Exception connection reset by peer. Next when i put a delay in the loop while sending/receiving messages on client side (say 5s), the client will send/receive for say 3-4 times and then the client encounters Exception connection reset by peer and now this time no such message on server side. Its really boggling me since I couldn't find the solution no matter what i try.
PS: I have timeout of 10 days for websocket server
The server side request handling is as follow:
std::cout << "Request Received" << std::endl;
Poco::Util::Application& app = Poco::Util::Application::instance();
try
{
std::cout << "Trying to connect..." << std::endl;
Poco::Net::WebSocket ws(request, response);
ws.setReceiveTimeout(Poco::Timespan(10, 0, 0, 0, 0)); //Timeout of 10 days
app.logger().information("WebSocket connection established!");
int flags, n;
do
{
char buffer[1024] = {'\0'};
std::cout << "Waiting for incoming frame" << std::endl;
n = ws.receiveFrame(buffer, sizeof(buffer), flags);
strncpy(buffer, "Hello Client!!", 1024);
ws.sendFrame(buffer, strlen(buffer), Poco::Net::WebSocket::FRAME_TEXT);
}
while (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);
std::cout << "Websocket Closed" << std::endl;
app.logger().information("WebSocket connection closed.");
}
catch (std::exception& e)
{
std::cout << "Exception " << e.what() << std::endl;
}
(As one can see, server will post a message when a websocket is closed but nothing is displayed when the client says connection reset by peer)
The poco websocket client side is:
HTTPClientSession cs("IP", port);
HTTPRequest request(HTTPRequest::HTTP_GET, "/?encoding=text",HTTPMessage::HTTP_1_1);
request.set("origin", "http://localhost");
HTTPResponse response;
bool run = true;
try {
WebSocket* m_psock = new WebSocket(cs, request, response);
char buffer[1024] = {'\0'};
std::string str = "Hello Server!!";
do {
char receiveBuff[256];
strncpy(buffer, str.c_str(), 1024);
int len=m_psock->sendFrame(buffer,strlen(buffer),WebSocket::FRAME_TEXT);
std::cout << "Sent bytes " << len << std::endl;
std::cout << "Sent Message: " << buffer << std::endl;
int flags=0;
int rlen=m_psock->receiveFrame(receiveBuff,256,flags);
std::cout << "Received bytes " << rlen << std::endl;
std::cout << receiveBuff << std::endl;
//std::cin >> str;
sleep(5);
} while (1);
m_psock->close();
}
catch (std::exception &e)
{
std::cout << "Exception " << e.what();
}
FYI: I can't process the connection reset by peer, because it directly goes to exception without printing received bytes as 0

Why do i get an error when i try to bind my UDP socket to a port with SFML?

I'm currently building a network prototype for SFML using UDP. I've created an application in which you can choose to be the server or the client. So, usually I start up 2 instances of the application, letting one be the server and the other be the client. I'm connecting to my local IP 127.0.0.1.
About 20 minutes ago, this EXACT code worked and I had no problems with it. I didn't change anything, but this code does not work anymore, and the program crashes when I call socket.bind() for the server. Client-side, no errors show up.
This is done in C++.
Does anyone know a possible cause for this? As far as I know, the port is not in use, either.
My client code:
void runUdpClient(unsigned short port){
sf::IpAddress server;
do
{
std::cout << "Type the address or name of the server to connect to: ";
std::cin >> server;
} while (server == sf::IpAddress::None);
sf::UdpSocket socket;
sf::Packet clientSendPacket;
std::string packetSendContent = "Packet data from the client";
clientSendPacket << packetSendContent;
if (socket.send(clientSendPacket, server, port) != sf::Socket::Done)
return;
std::cout << "Message sent to the server: \"" << packetSendContent << "\"" << std::endl;
// Maak variabelen
sf::IpAddress sender;
unsigned short senderPort;
sf::Packet clientReceivePacket;
std::string clientReceiveContent;
if (socket.receive(clientReceivePacket, sender, senderPort) != sf::Socket::Done)
return;
clientReceivePacket >> clientReceiveContent;
std::cout << "Message received from " << sender << ": \"" << clientReceiveContent << "\"" << std::endl;
}
My server code:
void runUdpServer(unsigned short port){
sf::UdpSocket socket;
if (socket.bind(port) != sf::Socket::Done)
std::cout << "Error binding socket for server";
return;
std::cout << "Server is listening to port " << port << ", waiting for a message... " << std::endl;
sf::Packet serverReceivePacket;
std::string serverReceiveContent;
sf::IpAddress sender;
unsigned short senderPort;
if (socket.receive(serverReceivePacket, sender, senderPort) != sf::Socket::Done)
std::cout << "Error receiving packet for server";
return;
serverReceivePacket >> serverReceiveContent;
std::cout << "Message received from client " << sender << ": \"" << serverReceiveContent << "\"" << std::endl;
sf::Packet serverSendPacket;
std::string serverSendContent = "Packet data from server";
serverSendPacket << serverSendContent;
if (socket.send(serverSendPacket, sender, senderPort) != sf::Socket::Done)
std::cout << "Error sending packet from server";
return;
std::cout << "Message sent to the client: \"" << serverSendContent << "\"" << std::endl;
}
In your server code, the if statements are missing braces, so you are ALWAYS executing return as soon as socket.bind() exits, whether it succeeds or fails. This code:
if (socket.bind(port) != sf::Socket::Done)
std::cout << "Error binding socket for server";
return;
Is the same as this code:
if (socket.bind(port) != sf::Socket::Done)
std::cout << "Error binding socket for server";
return;
Which is logically equivalent to this code:
if (socket.bind(port) != sf::Socket::Done) {
std::cout << "Error binding socket for server";
}
return;
Whitespace formatting is not important to C and C++. To perform multiple statements inside the body of an if block, you need explicit braces:
if (socket.bind(port) != sf::Socket::Done)
{
std::cout << "Error binding socket for server";
return;
}
Same with the if statements for your server's calls to socket.receive() and socket.send().
Your client code is not outputting any error messages if socket.send() or socket.receive() fail, those if statements are performing single statements in their body (namely, just return), so braces are optional.
Your server most likely shut down without closing the port properly.
If you wait a few minutes the port will be free to use again (takes about 2-3 minutes on my Ubuntu 16.04 system, might be different depending what OS you use)
Alternatively you can change the port you're using.
The problem was the formatting of the ifs and the returns. After hitting Ctrl+Shift+K, the code got formatted again and it worked.

winsock error 10049 trying to bind

I have a problem with server connection. When I try to bind the server to my external device IP I got a winsock error: 10049 Cannot assign requested address. Using localhost server works correctly.
This IP address: 192.168.0.202 ping successfully.
I worked on win8.1. I turned off firewall and windows defender and it did not help.
Code with server implementation has been taken from http://www.planetchili.net/forum/viewtopic.php?f=3&t=3433
#include "Server.h"
Server::Server(int PORT, bool BroadcastPublically) //Port = port to broadcast on. BroadcastPublically = false if server is not open to the public (people outside of your router), true = server is open to everyone (assumes that the port is properly forwarded on router settings)
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}
addr.sin_addr.s_addr = inet_addr("192.168.0.202");
addr.sin_port = htons(1234); //Port
addr.sin_family = AF_INET; //IPv4 Socket
sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
if (bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //Bind the address to the socket, if we fail to bind the address..
{
std::string ErrorMsg = "Failed to bind the address to our listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
if (listen(sListen, SOMAXCONN) == SOCKET_ERROR) //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections, if we fail to listen on listening socket...
{
std::string ErrorMsg = "Failed to listen on listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
serverptr = this;
}
bool Server::ListenForNewConnection()
{
SOCKET newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == 0) //If accepting the client connection failed
{
std::cout << "Failed to accept the client's connection." << std::endl;
return false;
}
else //If client connection properly accepted
{
std::cout << "Client Connected! ID:" << TotalConnections << std::endl;
Connections[TotalConnections] = newConnection; //Set socket in array to be the newest connection before creating the thread to handle this client's socket.
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(TotalConnections), NULL, NULL); //Create Thread to handle this client. The index in the socket array for this thread is the value (i).
//std::string MOTD = "MOTD: Welcome! This is the message of the day!.";
//SendString(TotalConnections, MOTD);
TotalConnections += 1; //Incremenent total # of clients that have connected
return true;
}
}
bool Server::ProcessPacket(int ID, Packet _packettype)
{
switch (_packettype)
{
case P_ChatMessage: //Packet Type: chat message
{
std::string Message; //string to store our message we received
if (!GetString(ID, Message)) //Get the chat message and store it in variable: Message
return false; //If we do not properly get the chat message, return false
//Next we need to send the message out to each user
for (int i = 0; i < TotalConnections; i++)
{
if (i == ID) //If connection is the user who sent the message...
continue;//Skip to the next user since there is no purpose in sending the message back to the user who sent it.
if (!SendString(i, Message)) //Send message to connection at index i, if message fails to be sent...
{
std::cout << "Failed to send message from client ID: " << ID << " to client ID: " << i << std::endl;
}
}
//std::cout << "Processed chat message packet from user ID: " << ID << std::endl;
if(Message == "go")
std::cout << "MESSAGE:GO!" << std::endl;
else if(Message == "left")
std::cout << "MESSAGE: GO LEFT!" << std::endl;
else if (Message == "right")
std::cout << "MESSAGE:GO RIGHT!" << std::endl;
else
std::cout << "MESSAGE:DO NOTHING!" << std::endl;
break;
}
default: //If packet type is not accounted for
{
std::cout << "Unrecognized packet: " << _packettype << std::endl; //Display that packet was not found
break;
}
}
return true;
}
void Server::ClientHandlerThread(int ID) //ID = the index in the SOCKET Connections array
{
Packet PacketType;
while (true)
{
if (!serverptr->GetPacketType(ID, PacketType)) //Get packet type
break; //If there is an issue getting the packet type, exit this loop
if (!serverptr->ProcessPacket(ID, PacketType)) //Process packet (packet type)
break; //If there is an issue processing the packet, exit this loop
}
std::cout << "Lost connection to client ID: " << ID << std::endl;
closesocket(serverptr->Connections[ID]);
return;
}
Any ideas?
The bind() function is used to specify which address of the server system is used to accept connections from remote clients, not to specify which remote client is allowed to connect to the server. The bind() function can only be used with addresses that are valid for the server itself, not for addresses of remote devices or hosts.
In order to limit which remote host is allowed to connect to your server, you need to accept the connection and validate the remote address at that time. If the address is not the correct one, the connection is closed.
In general, you want to use INADDR_ANY unless your server is multi-homed (more than one physical connection to more than one network), and only then if you are trying to restrict connections to one of the networks to which your server is attached.
Winsock returns the error flag 10049 (WSAEADDRNOTAVAIL) through its API WSAGetLastError whenever an application tries to bind to an invalid ip Addrress.
binding to a specific IP address means that whenever you run the program (server) the address should be valid (available) but however DHCP gives you dynamic ip addresses everytime you disconnect/connect your adapter so you the address you bound the server the previous time is not valid to correct it open cmd and enter :
ipconfig
you'll get the list of ip4/ip6 addresses then you can pick one of them and bind your server to however this method is really dull so the alternative is to bind to INADDR_ANY so you let the system do the job for you.
you need only from the client to enter the server address and port and connect.

Boost-Asio , multi-thread tcp server

I'm not able to succeed about boost-asio multithread program.
Since there is not any good example or documentation about this,
I want your help :)
Simply, I think this code do listen, but when I want to 'cout' buffer data,
it does not print anything or listening once and stopped.
My code is:
void Worker::startThread(int clientNumber) {
cout << "listening: "<< clients[clientNumber]->port << endl;
boost::asio::io_service io_service;
tcp::acceptor acc(io_service, tcp::endpoint(tcp::v4(),portNumber[clientNumber]));
socket_ptr sock(new tcp::socket(io_service));
acc.accept(*sock);
try
{
for (;;) {
char data[max_length];
boost::system::error_code error;
cout << "message?" << endl;
size_t length = sock->read_some(boost::asio::buffer(data), error);
cout << "message :)" << endl;
cout << data << endl;
if(error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
void Worker::start() {
cout << "Starting thread server" << endl;
for(int i=0; i<clients.size(); i++) {
boost::thread t(boost::bind(&Worker::startThread, this, i));
}
for(;;);
}
You haven't looked at the documentation very long if you don't see the multi-threaded examples
HTTP Server 3
An HTTP server using a single
io_service and a thread pool calling
io_service::run().
HTTP Server 2
An HTTP server using an
io_service-per-CPU design.
Keep in mind these examples use asynchronous methods, which is where the Boost.Asio library really shines.
You've basically copied the Blocking TCP Echo Server example yet you're unable to find a good example or documentation?
Anyway, I see some problems with your code:
Your saying your listening on clients[clientNumber]->port but the actual port you're listening on is portNumber[clientNumber];
You need to zero-terminate your data after read_some and before printing it;
As soon as the error == boost::asio::error::eof condition is true (the client disconnected) the thread will exit and therefore you'll not be able to (re)connect another client on that port;
You're only accepting the first connection / client, any other clients connecting on the same port will not have their messages handled in any way.