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.
Related
I'm writing a client/server application where the client and server should send data to each other via a TCP socket. The client should connect to the server and if the connection fails, it should wait a few seconds and then try again to connect to it (up to a certain number of tries).
This is the code I currently have:
const int i_TRIES = 5;
time_t t_timeout = 3000;
int i_port = 5678;
int i_socket;
string s_IP = "127.0.0.1";
for(int i = 0; i < i_TRIES; i++)
{
if((i_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "[Client]: Socket creation failed." << endl;
exit(EXIT_FAILURE);
}
memset(&server_address, '0', sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(i_port);
if(inet_pton(AF_INET, s_IP.c_str(), &server_address.sin_addr) <= 0)
{
cout << "[Client]: Invalid IP address." << endl;
exit(EXIT_FAILURE);
}
if(connect(i_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
if(i < i_TRIES - 2)
{
cout << "[Client]: Connection to server failed. Trying again in " << t_timeout << " ms." << endl;
close(i_socket);
sleep(t_timeout);
}
else
{
cout << "[Client]: Could not connect to server, exiting." << endl;
exit(EXIT_FAILURE);
}
}
else
{
cout << "[Client]: Successfully connected to server." << endl;
break;
}
}
// do stuff with socket
The issue I'm having is that the first call to connect() works as expected, it fails if there's no server and then the loop repeats, however, the second time connect() blocks forever (or at least for much longer than I want it to). Initially, my loop was just around the connect() if block (code below), and this also caused the same problem. After that I included the whole socket setup (the code above) in the loop, but that also didn't help. I also tried closing the socket after a failed connection, but this didn't help either.
Initial for loop:
// other stuff from above here
for(int i = 0; i < i_TRIES; i++)
{
if(connect(i_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
if(i < i_TRIES - 2)
{
cout << "[Client]: Connection to server failed. Trying again in " << t_timeout << " ms." << endl;
sleep(t_timeout);
}
else
{
cout << "[Client]: Could not connect to server, exiting." << endl;
exit(EXIT_FAILURE);
}
}
else
{
cout << "[Client]: Successfully connected to server." << endl;
break;
}
}
// do stuff with socket
Can I force connect() to return after a certain amount of time has passed? Or is there a way to get the connect() function to try multiple times on it's own? Or is there something I need to do to the socket to reset everything before I can try again? I hope this isn't a dumb question, I couldn't find any information about how to connect multiple times.
Thanks in advance!
Can I force connect() to return after a certain amount of time has passed?
No. You must put the socket into non-blocking mode and then use select() or (e)poll() to provide timeout logic while you wait for the socket to connect. If the connection fails, or takes too long to connect, close the socket, create a new one, and try again.
Or is there a way to get the connect() function to try multiple times on it's own?
No. It can perform only 1 connection attempt per call.
Or is there something I need to do to the socket to reset everything before I can try again?
There is no guarantee that you can even call connect() multiple times on the same socket. On some platforms, you must destroy the socket and create a new socket before you call connect() again. You should get in the habit of doing that for all platforms.
Put the socket into non-blocking mode and use select() to implement the timeout. Select for writeability on the socket. Note that you can decrease the platform connect timeout by this means, but not increase it.
The sleep() is pointless, just literally a waste of time.
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).
I'm working on a client application that sends sensor data one way to a remote server. After the initial login there is no return data from the server. My problem is when the ethernet is disconnected such as a hard disconnect i.e. wireless link goes down, my application does not get a error return value after attempting a 'send' call. I am using a single non-blocking socket instance. The thread checks for a 'recv' each loop using 'select'. It does eventually get an error on 'recv' but never on 'send'.
When the remote PC has a internet connectivity loss it will cause the program to be disconnected from the server for minutes to hours before it recognises the connection loss happened and switches to re-login the server. What can be done to help detect the hard disconnect?
void checkConnect(NTRIP& server)
{
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
if(FD_ISSET(server.socket, &Reader) )
{
int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
if(recvBytes == SOCKET_ERROR)
{
cout << "socket error on receive call from server " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else if(recvBytes == 0)
{
cout << "server closed the connection gracefully" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else //>0 bytes were received so read data if needed
{
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "select returned socket in error state" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select socket error " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect if no other data has been sent recently
if(server.connected_IP == true && getTimePrecise() - server.lastDataSendTime > 5.0)
{
char buf1[] = "hello";
cout << "checking send for error" << endl;
iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "server send WSAEWOULDBLOCK" << endl;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out " << iResult << " bytes" << endl;
}
server.lastDataSendTime = getTimePrecise();
}
}
It is not possible to detect disconnect until you try to send something.
The solution for you is the following:
You detect that you have received no data for a certain period of time and you want to check is the connection is alive.
You send some data to the server using send function. It could be protocol-specific ping packet or either garbage. The send function returns immediately, because it does not wait for actual data send. It only fills internal send buffer.
You begin waiting for socket read.
While you are waiting, OS tries to send the data in the send buffer to the server.
When OS detects that it cannot deliver data to the server, then the connection is marked as erroneous.
Now you will get an error when calling recv and send functions.
The send timeout is system specific and can be configured. Usually, it is about 20 seconds (Linux) - 2 minutes (Windows). It means that you need to wait a lot before you receive an error.
Notes:
You can also turn on TCP keep alive mechanism, but I don't recommend you to do this.
You can also modify TCP timeout intervals. It can be helpful when you want the connection to survive the temporary network disconnect.
That's how TCP works and is intended to work. You will get an error from a subsequent send, but never from the first send after the disconnect. There is buffering, and retry, and retry timeout to overcome before an error is signalled.
I'm kinda new to network programming and I'm trying to make a socket server that could handle multiple clients. The server will be a connection between players and a game engine for a text-based adventure, written in c++.
I got the code working for single clients, and for sending data between client and server. The next step in the implementation is to make it able to handle multiple clients. For what I understand fork is way to do this. I've got this code this far, but I can't for my life get it to work.
while (1) {
cout << "Server waiting." << endl;
n = sizeof(struct sockaddr_in);
if ((clientSocket = accept(servSocket, (struct sockaddr*) (&client), (socklen_t*) (&n))) < 0) {
cerr << "Error: " << errno << ": " << strerror(errno) << endl;
}
if(fork() == 0){
cout << "Child process created. Handling connection with << " << inet_ntop(AF_INET, &client.sin_addr, buff, sizeof(buff)) << endl;
close(servSocket);
}
string sendmsg;
string recvmsg;
int bytesRecieved = 0;
char package[1024];
string playerMessage;
while(1){
bytesRecieved = recv(clientSocket, package, 1024, 0);
for (int offset = 0; offset < bytesRecieved/sizeof(char); ++offset) {
playerMessage += package[offset];
}
cout << playerMessage;
cin >> sendmsg;
sendmsg += "\n";
send(clientSocket, sendmsg.c_str(), sendmsg.size(), 0);
}
}
close(clientSocket);
close(servSocket);
return 0;
I understand that the bind() and everything before that should happend before the main-loop with fork() in it, so I didn't bother to include that.
Thanks on beforehand!
Creating process per connection is a wrong way in most cases. What if you have 20'000 players? Context switching for 20'000 processes makes too much overhead slowing down the server.
Consider using async programming. boost::asio is one of the best choices then.
I am having trouble using the connect() function. My code was completely working before, but now I have moved to a different physical network and my blocking call to connect() no longer works, and just seems to hang indefinitely. Receiving broadcasts over UDP still works fine. Going back to the old network it works fine again. I cant for the life of me figure out why it works on one network and not the other. I have checked firewall settings and they are correct. What could be going on?
I have a pre-defined port being used and I am getting the address from the broadcast. I use recievefrom to receive the broadcast and set the outgoing ip address from it
ret = recvfrom (bcast, bcast_read,sizeof(j4cDAC_broadcast),0,(sockaddr*)&from,&size);
to.sin_addr = from.sin_addr;
local.sin_addr.s_addr = inet_addr("0.0.0.0");
Then for the TCP connection I have
dac = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// cout << "SOCKET\n";
if (dac == INVALID_SOCKET)
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "TCP socket failed: " << WSAGetLastError();
connected_ = false;
return(1);
}
//set SO_REUSEADDR on a socket to true (1):
bool optval = true;
setsockopt(dac, SOL_SOCKET,SO_DONTLINGER,(const char*)&optval, sizeof(optval));
int pies = setsockopt(dac, SOL_SOCKET,SO_REUSEADDR,(const char*)&optval, sizeof(optval) );
if (pies == SOCKET_ERROR )
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "SETSOCKOPT ERROR: " << WSAGetLastError() << endl;
} // */
local_T = local;
local_T.sin_port = htons ((short)TCPport);
//bind the tcp socket
bndt = bind(dac,(SOCKADDR*) &local_T,sizeof(local_T) );
if (bndt == SOCKET_ERROR )
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "BIND TCP FAILED: " << WSAGetLastError();
if (WSAGetLastError() == WSAEACCES)
cout << "ACCESS DENIED";
cout << endl;
SetConsoleTextAttribute(console,(WORD)7);
shutdown(dac,2);
closesocket(dac);
connected_ = false;
return 1;
}
c = connect(dac, (sockaddr*) &to, size); // <------- This hangs
if (c == SOCKET_ERROR)
{
cout << "connection problem: " << WSAGetLastError() <<endl;
}
connected_ = true;`
I found this to be an issue with VMWare virtual networking devices. Even though I had no virtual machines running, after much testing of various things, I found the device broadcast was being received on one of the virtual networking interfaces from VMWare somehow. Disabling these two devices has fixed this issue.