I want to send random trigger signals (A and B) from Matlab to a C++ Code. The point where I stuck now is, that whenever I am not sending this trigger signal/message, the C++ Code keeps waiting for it and doesn't continue its process.
How can I make the C++ Code keep running (to collect data) without waiting for the next trigger message. Because now only once it receives the message (UDP transfers trigger signal) it gives me the specific outcome.
----------- BEGIN MATLAB CODE ---------------------
send_trigger_signal = instrfind('Type', 'udp', 'LocalHost', '127.0.0.1','RemoteHost', '192.168.0.100', 'RemotePort', 8888, 'LocalPort', 8844, 'Tag', '');
% Create the udp object if it does not exist otherwise use the object that was found.
if isempty(send_trigger_signal)
send_trigger_signal = udp('127.0.0.1', 'RemotePort', 8888, 'LocalPort', 8844);
else
fclose(send_trigger_signal);
send_trigger_signal = send_trigger_signal(1);
end
send_trigger_signal.DatagramTerminateMode='off';
send_trigger_signal.Timeout=0.0001;
send_trigger_signal.Timerperiod=0.01;
%send_trigger_signal.
% Connect to instrument object, send_trigger_signal.
fopen(send_trigger_signal);
% Communicating with instrument object, send_trigger_signal.
on_trigger_command=typecast(swapbytes(uint16([1 1 0 0])),'uint8'); %trigger on
off_trigger_command=typecast(swapbytes(uint16([0 0 0 0])),'uint8'); %trigger off
while(true)
for i=1:1
fprintf(send_trigger_signal, 'A');
WaitSecs(5);
end
end
fclose(send_trigger_signal);
send_trigger_signal=instrfindall;
delete(send_trigger_signal);
instrfindall;
----------- END MATLAB CODE ---------------------
This is the C++ code which should receive the random trigger signals from Matlab (A and B), while collecting gyro data between those signals.
To test it here the message is send every 5sec. The problem is that I cannot collect the gyro data in within those 5sec. The UDP communication is interrupting the data collection - because it is waiting those 5sec.
----------- START C++ CODE ---------------------
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
#define BUFLEN 512
#define PORT 8888
int receiver(void)
{
int value = 5;
system("title UDP Server");
sockaddr_in server, client;
// initialise winsock
WSADATA wsa;
printf("Initialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code: %d", WSAGetLastError());
exit(0);
}
printf("Initialised.\n");
// create a socket
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket: %d", WSAGetLastError());
}
printf("Socket created.\n");
// prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code: %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done.");
while (true)
{
printf("Waiting for data...");
fflush(stdout);
char message[BUFLEN] = {};
// try to receive some data, this is a blocking call
int message_len;
int slen = sizeof(sockaddr_in);
if (message_len = recvfrom(server_socket, message, BUFLEN, 0, (sockaddr*)&client, &slen) == SOCKET_ERROR)
{
printf(message);
printf("recvfrom() failed with error code: %d", WSAGetLastError());
exit(0);
}
if (message[0] == 'A')
{
value = 6;
break;
}
if (message[0] == 'B')
{
value = 7;
break;
}
// print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
printf("Data: %s\n", message);
return 0;
}
closesocket(server_socket);
WSACleanup();
return value;
}
int main()
{
while (true)
{
// Reading some gyro data here
// Listening UDP
receiver();
}
return 0;
}
----------- END C++ CODE ---------------------
With a few structural tweaks:
Using non-blocking socket.
You don't want to restart winsock and rebind the socket every time you read from it, so that's spun off to different functions (an RAII wrapper class in the case of winsock).
C-style IO replaced with C++ IO.
exit(0) means the program succeeded, but was used in many cases where failure occurred. Consistently using exit(EXIT_FAILURE);. Might be worth throwing an exception, but it's annoying to get the error code into the exception text.
Removed some of the output because it would be spammed out now that the receive function can immediately return .
Your program could look something like this:
#include <iostream>
#include <winsock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib") // Winsock Library
#pragma warning(disable:4996)
// using modern C++ constants
constexpr int BUFLEN = 512;
constexpr int PORT = 8888;
//RAII wrapper to make sure winsock is created and disposed of responsibly
struct winsock_RAII
{
winsock_RAII()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
std::cerr << "Failed to initialize winsock. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
}
~winsock_RAII()
{
WSACleanup(); // what are we gonna do if it fails? Not much we can do.
}
};
//socket initialization
SOCKET init_sock()
{
SOCKET server_socket;
if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
u_long iMode = 1;
//setr socket non-blocking
if (ioctlsocket(server_socket, FIONBIO, &iMode) != NO_ERROR)
{
std::cerr << "Failed to get socket. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
// prepare the sockaddr_in structure
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
// bind
if (bind(server_socket, (sockaddr*) &server, sizeof(server)) == SOCKET_ERROR)
{
std::cerr << "Bind failed. Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return server_socket;
}
// read from socket
int receiver(SOCKET server_socket)
{
// try to receive some data, this is a non-blocking call
int slen = sizeof(sockaddr_in);
sockaddr_in client;
char message[BUFLEN + 1]; // no need to clear the whole buffer. We'll know
// exactly where to put the null thanks to message_len
// +1 makes sure we have room for terminator
int message_len = recvfrom(server_socket, message,
BUFLEN,
0,
(sockaddr*) &client,
&slen);
int value = 5;
if (message_len != SOCKET_ERROR)
{
message[message_len] = '\0'; // place terrminator
if (message[0] == 'A')
{
value = 6;
}
if (message[0] == 'B')
{
value = 7;
}
// print details of the client/peer and the data received
std::cout << "Received packet from " << inet_ntoa(client.sin_addr) << ':' << ntohs(client.sin_port) << '\n'
<< "Data: " << message << '\n';
}
else if (WSAGetLastError() != WSAEWOULDBLOCK)
{
// printf(message); no point to printing message. There isn't one
std::cerr << "recvfrom() failed . Error Code: " << WSAGetLastError() << '\n';
exit(EXIT_FAILURE);
}
return value;
}
int main()
{
winsock_RAII winsock; // scoped winsock initializer
SOCKET server_socket = init_sock();
while (true)
{
// Reading some gyro data here
receiver(server_socket);
}
closesocket(server_socket);
return 0;
}
You might want to use select with a short timeout to throttle the loop because it can be a serious and unnecessary CPU-eater if the gyro reading code is also quick.
Related
I am coding in C++ using winsock api. I am making a multi- client server chat. The problem that I am encountering in my code is that my server is able to send the message to the client only once. But I want this to happen multiple times. I cannot put accept() function out of infinite loop in server code. I have used select() for multi client. I am doing it without threading.
Server:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
// See who's talking to us
int socketCount = select(0, ©, nullptr, nullptr, nullptr);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
//Send a new message
string mssg;
getline(cin, mssg);
int bytes = send(sock, mssg.c_str(), mssg.size() + 1, 0);
for (int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening && outsock != sock) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
}
Client code:
#include<iostream>
#include<ws2tcpip.h>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
void main() {
string ipAddress = "127.0.0.1"; //IP Address of the server
int port = 54000; //Listening port on the sever
//Initialize Winsock
WSADATA data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << " Can't initialize winsock " << endl;
return;
}
//Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
cerr << "Can't create a socket " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Fill in a hint structure
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
//Connect to the server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << " Can't connect to the server " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Do-While loop to send and receive data
//char b[4096];
//int bytes = recv(sock,b,4096, 0);
//cout << string(b, 0, bytes) << endl;
char buff[4096];
string userInput;
do {
//Prompt the user
//cout << ">";
//getline(cin, userInput);
//Send the result
//int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
//if (sendResult != SOCKET_ERROR) {
//ZeroMemory(buff, 0);
int bytesrecieved = recv(sock, buff, 4096, 0);
if (bytesrecieved > 0) {
//Echo response to console
cout << "SERVER> " << string(buff, 0, bytesrecieved) << endl;
}
//}
} while (true);
//Shut down everything
closesocket(sock);
WSACleanup();
}
EDIT:
You should do some modifications :
Use timeval for select to avoid the blocking select (wait until a
new connection was made or there is something to read).
Move the read/send message section out of the for loop.
Separate key input processing in an other thread.
Use a safe queue to share the input between the input thread and the communciation one(main thread).
Here is an example:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#include <thread>
#include <mutex>
#include <list>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
class safe_queue {
mutex m;
list<string> str_queue;
public:
safe_queue() {};
void add(const string &s) {
const lock_guard<mutex> lock(m);
str_queue.push_back(s);
}
bool pop( string &s ) {
const lock_guard<mutex> lock(m);
if (!str_queue.empty()) {
s = str_queue.front();
str_queue.pop_front();
return true;
}
return false;
}
};
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return 0;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
safe_queue sq;
auto io_thread = thread([&] {
string s;
while (running && getline(std::cin, s, '\n')){
sq.add(s);
}
});//thread.
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
timeval tv = {0,0};
// See who's talking to us
int socketCount = select(0, ©, nullptr, nullptr, &tv);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
}//for.
string mssg;
if (sq.pop(mssg) ) {
std::cout << "Send :" << mssg << endl;
for (u_int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}//while
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
I have adapted the code from http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html (selectserver.c -- a cheezy multiperson chat server) to compile on Windows. The complete code follows below. I compile using gcc version 6.1.0 (x86_64-posix-seh, Built by MinGW-W64 project). I compile using gcc6.1.0 on Linux, too.
Basically, you run it, telnet 2 or more times to port 9034, and whatever you type in one telnet session gets echoed to the other telnet sessions (depending on the system, one has to type Enter before it gets echoed - on Windows it echoes every character typed).
Now the problem :
On Linux AMD64 or ARM, I can connect to it from localhost and from another system, be that Windoes or Linux. On Windows, it only works on localhost, and I fail to understand why. The fact that hints.ai_flags = AI_PASSIVE; is specified makes it listen on all interfaces, if I understand things correctly.
The MSDN doc states:
Setting the AI_PASSIVE flag indicates the caller intends to use the returned socket address structure in a call to the bind function.
When the AI_PASSIVE flag is set and pNodeName is a NULL pointer, the IP address portion of the socket address structure is set to INADDR_ANY for IPv4 addresses and IN6ADDR_ANY_INIT for IPv6 addresses.
The code reads :
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0)
How do I make this behave correctly on Windows?
It is compiled with :
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\chatserver.o" "..\src\chatserver.cpp"
and linked with
g++ -mwindows -o chatserver.exe "src\chatserver.o" -lws2_32
What do I need to change in the code please?
This is the complete code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifdef _WIN32
#include <ws2tcpip.h>
#endif
#define PORT "9034" // port we're listening on
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); }
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
#ifdef _WIN32
WSADATA wsaData; // Initialize Winsock
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (NO_ERROR != nResult) {
printf ("Error occurred while executing WSAStartup().");
}
#endif
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR, below
int i, j, rv;
struct addrinfo hints, *ai, *p;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) { continue; }
// lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int));
//setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, "1", sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
// if we got here, it means we didn't get bound
if (p == NULL) {
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); // all done with this
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);
if (newfd == -1) {
perror("accept");
}
else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
std::cout << "selectserver: new connection on socket " << newfd;
/*
printf("selectserver: new connection from %s on "
"socket %d\n",
inet_ntop(remoteaddr.ss_family,get_in_addr((struct sockaddr*)&remoteaddr),remoteIP, INET6_ADDRSTRLEN),newfd);
*/
}
}
else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
std::cout << "selectserver: socket " << i << " hung up";
}
else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
}
else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener and ourselves
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)--and you thought it would never end!
return 0;
}
getaddrinfo() can return multiple IP addresses. You are correctly looping through all of the returned addresses, but you are breaking the loop after the first successful bind(), and then you are calling listen() on that one single socket, regardless of its socket family. Since you are using AF_UNSPEC when calling getaddrinfo(), it is possible that it is returning BOTH INADDR_ANY for IPv4 AND IN6ADDR_ANY_INIT for IPv6.
Change your code to listen on every IP address that getaddrinfo() returns, and to keep track of those sockets so you can use all of them in your select() loop. If you just wanted to listen on either INADDR_ANY or IN6ADDR_ANY_INIT, there would be no point in using getaddrinfo() at all, as you could just hard-code the socket()/bind() calls for those two addresses and get rid of the loop altogether. The purpose of using getaddrinfo() in this manner is to let it decide what you should be listening on, given the AI_PASSIVE hint you provided. Don't make assumptions about its output.
You also cannot use fdmax on Windows, so you need to re-write your select() loop. Sockets on Windows do not use file descriptors, so you can't simply loop from 0 <= fdmax when calling FD_ISSET(), and the first parameter of select() is ignored as well. I suggest not storing your active socket descriptors/handles in a master fd_set to begin with. Use a std::list or other suitable container instead, and then dynamically create a new fd_set whenever you need to call select(). This would be more portable across different platforms.
Try something more like this:
#include <unistd.h>
#include <sys/types.h>
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
inline int closesocket(int s) { return close(s); }
inline int getLastSocketError() { return errno; }
#endif
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
inline int getLastSocketError() { return WSAGetLastError(); }
#endif
#include <iostream>
#include <list>
#include <algorithm>
#include <utility>
#define PORT "9034" // port we're listening on
#ifdef _WIN32
#define SELECT_MAXFD 0
#else
#define SELECT_MAXFD fdmax+1
#endif
enum eSocketType { stListener, stClient };
struct SocketInfo
{
SOCKET sckt;
eSocketType type;
};
SocketInfo makeSocketInfo(SOCKET sckt, eSocketType type) {
SocketInfo info;
info.sckt = sckt;
info.type = type;
return info;
}
// get sockaddr, IPv4 or IPv6:
void* get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
std::list<SocketInfo> master; // socket descriptors
std::list<SocketInfo>::iterator i, j;
SOCKET sckt, newsckt; // socket descriptors
fd_set read_fds; // temp file descriptor list for select()
#ifndef _WIN32
int fdmax; // maximum file descriptor number
#endif
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
int nbytes;
char ipAddr[INET6_ADDRSTRLEN];
int yes = 1; // for setsockopt() SO_REUSEADDR, below
int rv;
struct addrinfo hints, *ai, *p;
#ifdef _WIN32
WSADATA wsaData; // Initialize Winsock
rv = WSAStartup(MAKEWORD(2,2), &wsaData);
if (NO_ERROR != rv) {
std::cerr << "WSA startup failed, error: " << rv << std::endl;
return 1;
}
#endif
// get us the listening sockets and bind them
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
rv = getaddrinfo(NULL, PORT, &hints, &ai);
if (rv != 0) {
std::cerr << "selectserver: getaddrinfo failed, error: " << gai_strerror(rv) << std::endl;
return 2;
}
for(p = ai; p != NULL; p = p->ai_next) {
sckt = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (INVALID_SOCKET == sckt) {
std::cerr << "selectserver: socket failed, error: " << getLastSocketError() << std::endl;
continue;
}
// lose the pesky "address already in use" error message
setsockopt(sckt, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int));
//setsockopt(sckt, SOL_SOCKET, SO_REUSEADDR, "1", sizeof(int));
if (bind(sckt, p->ai_addr, p->ai_addrlen) < 0) {
std::cerr << "selectserver: bind failed, error: " << getLastSocketError() << std::endl;
closesocket(sckt);
continue;
}
// listen
if (listen(sckt, 10) < 0) {
std::cerr << "selectserver: listen failed, error: " << getLastSocketError() << std::endl;
closesocket(sckt);
continue;
}
/*
std::cout << "selectserver: listening on IP " << inet_ntop(p->ai_family, get_in_addr(p->ai_addr), ipAddr, sizeof(ipAddr)) << ", socket " << sckt << std::endl,
*/
// add the listener to the master list
master.push_back(makeSocketInfo(sckt, stListener));
}
freeaddrinfo(ai); // all done with this
// if we got here, it means we didn't get bound
if (master.empty()) {
std::cerr << "selectserver: failed to bind" << std::endl;
return 3;
}
// main loop
while (1) {
#ifndef _WIN32
fdmax = 0;
#endif
FD_ZERO(&read_fds);
for (i = master.begin(); i != master.end(); ++i) {
sckt = i->sckt;
FD_SET(sckt, &read_fds);
#ifndef _WIN32
fdmax = std::max(fdmax, sckt);
#endif
}
if (select(SELECT_MAXFD, &read_fds, NULL, NULL, NULL) < 0) {
std::cerr << "select failed, error: " << getLastSocketError() << std::endl;
return 4;
}
// run through the existing connections looking for data to read
for(i = master.begin(); i != master.end(); ) {
sckt = i->sckt;
if (!FD_ISSET(sckt, &read_fds)) {
++i;
continue;
}
// we got one!!
if (stListener == i->type) {
// handle a new connection
addrlen = sizeof(remoteaddr);
newsckt = accept(sckt, (struct sockaddr *)&remoteaddr, &addrlen);
if (INVALID_SOCKET == newsckt) {
std::cerr << "accept failed on socket " << sckt << ", error: " << getLastSocketError() << std::endl;
}
else {
master.push_back(makeSocketInfo(newsckt, stClient)); // add to master list
std::cout << "selectserver: new connection, socket " << newsckt << std::endl;
/*
std::cout << "selectserver: new connection from " << inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), ipAddr, sizeof(ipAddr)) << ", socket " << newsckt << std::endl,
*/
}
}
else {
// handle data from a client
nbytes = recv(sckt, buf, sizeof(buf), 0);
if (nbytes <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
std::cout << "selectserver: socket " << sckt << " disconnected" << std::endl;
}
else {
std::cerr << "selectserver: recv failed on socket " << sckt << ", error: " << getLastSocketError() << std::endl;
}
closesocket(sckt); // bye!
i = master.erase(i); // remove from master list
continue;
}
// send to everyone!
// except a listener and ourselves
for(j = master.begin(); j != master.end(); ) {
if ((j->sckt != sckt) && (stClient == j->type)) {
if (send(j->sckt, buf, nbytes, 0) < 0) {
std::cerr << "selectserver: send failed on socket " << j->sckt << ", error: " << getLastSocketError() << std::endl;
closesocket(j->sckt); // bye!
j = master.erase(j); // remove from master list
continue;
}
}
++j;
}
}
++i;
}
}
for(i = master.begin(); i != master.end(); ++i) {
closesocket(i->sckt);
}
#ifdef _WIN32
WSACleanup();
#endif
return 0;
}
If you are running the code on a system that supports dual-stack sockets (like Windows), you can change AF_UNSPEC to AF_INET6 (or just hard-code socket()/bind() without using getaddrinfo()) to create only IPv6 listener(s) on IN6ADDR_ANY_INIT, and then disable the IPV6_V6ONLY socket option on them. This will allow IPv6 listen sockets to accept both IPv4 and IPv6 clients, reducing the number of listen sockets you need to create.
I am trying to program a udp client and server that will return the offset between the ntp time and boxtime. I cannot get my server to correctly receive data. I am testing it with Microsoft Unit tests, and when I try and test the server and client the test actually fails. If I run the test I just get the error message:
"The active Test Run was aborted because the execution process exited unexpectedly. To investigate further, enable local crash dumps either at the machine level or for process vstest.executionengine.x86.exe. Go to more details: http://go.microsoft.com/fwlink/?linkid=232477"
If I debug I find that recvfrom function in the server returns 0, so it just exits.
Here is my code for the server:
#pragma once
#include <iostream>
#include "NtpServer.h"
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winsock.h>
#include <errno.h>
using std::chrono::system_clock;
namespace ntp
{
struct sockaddr_in server;
struct sockaddr_storage client;
//constructor to create ntp server
NtpServer::NtpServer(u_short portnum, const std::chrono::nanoseconds desiredOffset) : portnum(0), client_length(0), bytes_received(0), current_time(0), desiredOffset(0)
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
std::cerr << "Could not open Windows connection." << std::endl;
exit(0);
}
memset((void *)&server, '\0', sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(portnum);
server.sin_addr.s_addr = htonl(INADDR_ANY);
sd = WSASocket(AF_INET, SOCK_DGRAM, 17, NULL, 0, NULL);
if (sd == INVALID_SOCKET)
{
std::cerr << "Could not create socket." << std::endl;
WSACleanup();
exit(0);
}
if (bind(sd, reinterpret_cast<SOCKADDR *>(&server),
sizeof(server)) == -1)
{
std::cerr << "Could not bind name to socket" << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
getResult(desiredOffset);
}
NtpServer::~NtpServer()
{
closesocket(sd);
WSACleanup();
}
void NtpServer::getResult(const std::chrono::nanoseconds desiredOffset)
{
ntp_data ntpData = ntp_data();
//set up timeout with blocking
fd_set fds;
int n;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(sd, &fds);
tv.tv_sec = 10; // 10 Secs Timeout
tv.tv_usec = 0;
n = select(sd, &fds, NULL, NULL, &tv);
if (n == 0)
{
exit(0);
}
while (1)
{
//client_length = sizeof(client);
int len = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
bytes_received = recvfrom(sd, sendBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &len);
if (bytes_received == SOCKET_ERROR)
{
std::cerr << "Could not receive datagram." << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
if (bytes_received < NTP_PACKET_MIN)
{
continue;
}
/* Check for time request */
if (strcmp(readBuffer, "GET TIME\r\n") == 0)
{
/* Get current time */
system_clock::time_point now = std::chrono::system_clock::now();
auto timepointoffset = (now + desiredOffset).time_since_epoch();
double current_value = std::chrono::duration_cast<std::chrono::duration<double>>(timepointoffset).count();
unpack_ntp(&ntpData, (unsigned char *)readBuffer, bytes_received);
make_packet(&ntpData, NTP_CLIENT, current_value);
pack_ntp((unsigned char *)sendBuffer, NTP_PACKET_MIN, &ntpData);
/* Send data back */
if (sendto(sd, sendBuffer,
(int)sizeof(sendBuffer), 0,
(struct sockaddr *)&client, client_length) !=
(int)sizeof(current_time))
{
std::cerr << "Error sending datagram." << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
}
}
closesocket(sd);
WSACleanup();
}
}
Edit: I changed the way I did the timeout with a select statement, and recvfrom "if" statements.
bytes_received = recvfrom(sd, sendBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < NTP_PACKET_MIN)
{
std::cerr << "Could not receive datagram." << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
Should be:
bytes_received = recvfrom(sd, sendBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received == SOCKET_ERROR)
{
int err = WSAGetLastError();
// Handle WSAETIMEDOUT here if necessary
std::cerr << "Could not receive datagram, error: " << err << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
if (bytes_received < NTP_PACKET_MIN)
{
// print/log a warning here
continue;
}
This aborts the receive loop if a call to recvfrom() fails, but simply ignores invalid packets (those less than the minimum length).
Another issue:
unpack_ntp(&ntpData, (unsigned char *)readBuffer, bytes_received);
make_packet(&ntpData, NTP_CLIENT, current_value);
pack_ntp((unsigned char *)sendBuffer, NTP_PACKET_MIN, &ntpData);
/* Send data back */
if (sendto(sd, sendBuffer,
(int)sizeof(sendBuffer), 0,
(struct sockaddr *)&client, client_length) != (int)sizeof(current_time))
{
std::cerr << "Error sending datagram." << std::endl;
closesocket(sd);
WSACleanup();
exit(0);
}
You're sending the entire sendBuffer; you should probably send only the size of the NTP packet. (Hopefully pack_ntp returns the packet size and you can use that). Also, you're comparing the sent size with sizeof(current_time) which makes zero sense. You should compare against the size of the buffer sent.
There are other minor issues, but these are the big ones that jump out.
You have this line of code:
setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
If the 10 second timeout elapses because no data was received, recvfrom() will return -1 and WSAGetLastError() will return 10060. Your code is exiting in that situation:
bytes_received = recvfrom(sd, sendBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &len);
if (bytes_received == SOCKET_ERROR)
{
std::cerr << "Could not receive datagram." << std::endl;
closesocket(sd);
WSACleanup();
exit(0); // <-- here
}
Even if select() times out, you are exiting as well:
n = select(sd, &fds, NULL, NULL, &tv);
if (n == 0)
{
exit(0); // <-- here
}
Make sure there is another application actually sending data to your UDP app.
I'm trying to make a chess game, through sockets.
There is a server that is responsible for sending the board to the players, to get the input and response and so on..
I've tried to create a client-server (actually 2clients and server) but it doesn't work.
The clients connect to the server properly, but the data that is delieved doesn't correct.
For example, I send "E2-C3" from the client ; the recv result (on the server side) is always 0, or it prints garbage.
Client :
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sys/types.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
using namespace std;
#define SERVER_IP "1.1.1.1"
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024
// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30
// client side
#define MOVE 10
int __cdecl main()
{
WSADATA info;
int errorDATA; // configuriation
int socketCreate; // create the socket - empty
SOCKADDR_IN ClientService; // configuriation (stage 3) - data of the server.
int connectResult;
char sendBuf[1024], recvbuf[1024];
int iResult;
/*Configuration*/
errorDATA = WSAStartup(MAKEWORD(2, 2), &info);
if (errorDATA == INVALID_SOCKET)
{
printf("WSAStartup failed with error : %d\n", errorDATA);
return -1;
}
/*Create empty socket*/
socketCreate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // creating the socket "Clean - empty"
if (socketCreate == INVALID_SOCKET)
{
printf("Error number %d in creating socket!\n", WSAGetLastError());
return -1;
}
printf("Creating socket SUCCEEDED!\n");
/*Confugirate the created socket*/
ClientService.sin_family = AF_INET;
ClientService.sin_addr.s_addr = inet_addr(SERVER_IP); // server's ip
ClientService.sin_port = htons(SERVER_PORT);
/*Asking for connection*/
connectResult = connect(socketCreate, (struct sockaddr*) &ClientService, sizeof(ClientService));
while (1)
{
cout << "Please enter a move : " << endl;
cin >> sendBuf;
iResult = send(socketCreate, sendBuf, (int)strlen(sendBuf), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(socketCreate);
WSACleanup();
return 1;
}
// MOVE
iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
if (iResult > 0)
{
if (recvbuf[0] == '0' && recvbuf[1] == '0')
{
cout << "You've entered an illegal move. Please try again." << endl;
continue;
}
else if (recvbuf[0] == '2' && recvbuf[1] == '0')
{
// print the board.
bool keepGoing = 0;
do
{
iResult = recv(socketCreate, recvbuf, strlen(recvbuf), 0);
if (iResult > 0)
{
if (recvbuf[0] == '1' && recvbuf[1] == '5')
{
keepGoing = true;
continue;
}
}
} while (!keepGoing);
}
}
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
}
printf("Bytes Sent: %ld\n", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(socketCreate, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(socketCreate);
WSACleanup();
return 1;
}
// cleanup
closesocket(socketCreate);
WSACleanup();
cin.get();
system("pause");
return 0;
}
server:
#include <iostream>
#include <winsock2.h>
#include <string>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#define MAX_NUMBER_OF_PLAYERS 1
#define BUFFER_SIZE 1024
#define LIMIT 1
// server side
#define INVALID_MOVE 00
#define PLEASE_ENTER_A_MOVE 15
#define PRINT_BOARD 20
#define END_GAME 30
// client side
#define MOVE 10
using namespace std;
int main()
{
WSADATA WsaDat;
SOCKET clientsock[2];
int minsock = 0;
int numsocks = MAX_NUMBER_OF_PLAYERS;
if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
{
std::cout << "WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cout << "Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKADDR_IN serverInf;
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(8888);
if (bind(serverSocket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
{
std::cout << "Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
listen(serverSocket, 5);
clientsock[0] = accept(serverSocket, NULL, NULL);
cout << "Client 1 has connected." << endl;
clientsock[1] = accept(serverSocket, NULL, NULL);
cout << "Client 2 has connected." << endl;
for (int i = 0; i < 2; i++)
{
cout << clientsock[i] << endl;
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode = 1;
ioctlsocket(serverSocket, FIONBIO, &iMode);
char client1_buffer[BUFFER_SIZE];
char client2_buffer[BUFFER_SIZE];
char* clientBuffer;
// until there isn't a mate.
bool gameRunning = true;
// user represents if it's user1 (0), or user2(1)
bool user = 0;
while (gameRunning)
{
if (!user)
clientBuffer = client1_buffer;
else
clientBuffer = client2_buffer;
int in = recv(clientsock[0], client1_buffer, 0, 0);
cout << in << endl;
if (in > 0)
{
// CHECKS
// MOVE COMMAND
// IF worked, send the board to both clients. if current user = 1 ==> do user to 0 | if the user = 0 => do user to 11
// ELSE, send the current client (clientsock[user]) Error message and ask for a command again.
cout << client1_buffer << endl;
cout << " IN RECV";
char* szMessage = "15";
send(clientsock[0], szMessage, strlen(szMessage), 0);
}
else if (in == 0)
{
// The connection has closed.
// REMEMBER : SAVE THE GAME SITUATION.
}
else
{
printf("recv failed: %d\n", WSAGetLastError());
// SEND ERROR MESSAGE TO BOTH CLIENTS
}
}
// Shutdown our socket
shutdown(serverSocket, SD_SEND);
// Close our socket entirely
closesocket(serverSocket);
WSACleanup();
system("pause");
return 0;
}
What Hans said. plus this:
int in = recv(clientsock[0], client1_buffer, 0, 0);
Your probably want to say this:
int in = recv(clientsock[0], client1_buffer, BUFFER_SIZE, 0);
Also, you are making a fundamental error that a lot of people make with sockets. You are assuming that your recv call on your server will return as many bytes was passed to the corresponding send call by the client. Fragmentation, segmentation, and other network stuff may cause you to receive only a partial amount of the message that was sent on the other node's send call. (Hence, TCP is a stream protocol as they say).
You should diligently check the return value from recv. Write your code as if the sender was only to going to send 1 byte at a time. You should put delimiters between your messages (a null char is fine) and loop on recv until you get a complete message. Otherwise, what seems to work fine on your own PC and on the local subnet will have strange bugs when deployed to the internet.
In the server file change
int in = recv(clientsock[0], client1_buffer, 0,0);
to
int in = recv(clientsock[0], client1_buffer, 1024,0);
change is the length of the date to be received
The problem is
strlen(recvbuf)
You probably mean
sizeof(recvbuf)
strlen(recvbuf) does not makes sense before you received the data, because your buffer contains just garbage, thus strlen() is just a bad random number generator. strlen(recvbuf) would make sense after you received the data if you would have made sure it was filled with 0. That not being the case, you can use the return value of recv() to find out how many bytes you received.
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.