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.
Related
I want to create two projects with this code so that they can chat with each other, but no matter how much I send, the data does not reach the other client.
I've been thinking and trying for hours on this problem, but it doesn't work. Various multicast chat programs on the web are written in languages other than C++, some use threads and some do not. To the best of my knowledge right now, I can't understand the codes on the web.
For fear of lengthy code, the basic header file and error output function have been omitted.
// header file and function declaration
#define MAXBUF 80
SOCKADDR_IN maddr;
int main(int argc, char* argv[]) {
int port;
cout << "input port number" << endl;
cin >> port;
cout << "use port : " << port << endl;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa))
{
err_display("WSAStartup");
return -1;
}
//create send socket
SOCKET r_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r_sock == INVALID_SOCKET)
{
err_display(" recv socket");
return -1;
}
//create recv socket
SOCKET s_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s_sock == INVALID_SOCKET)
{
err_display(" send socket");
return -1;
}
// bind
maddr.sin_family = AF_INET;
maddr.sin_port = htons(port);
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(r_sock, (SOCKADDR*)&maddr, sizeof(maddr))) {
err_display("bind");
return -1;
}
// Join the Multicast address
const char* mip = "236.0.0.1";
IP_MREQ mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // s_addr = 주소
// Setting Multicast address
if (!(inet_pton(AF_INET, mip, &mreq.imr_multiaddr))) {
err_display("inet_pton");
return -1;
}
// JOIN
if (setsockopt(r_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq))) {
err_display("setsockopt");
return -1;
}
while (true) {
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, &sendf, (LPVOID)s_sock, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, &recvf, (LPVOID)r_sock, 0, NULL);
}
closesocket(r_sock);
closesocket(s_sock);
WSACleanup();
return 0;
}
unsigned __stdcall sendf(LPVOID arg) // send thread function
{
SOCKET s_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int sendlen;
while (1)
{
// send
char mesbuf[MAXBUF];
if (fgets(mesbuf, MAXBUF - 1, stdin) == NULL)
break;
cout << "send Thread" << endl;
sendlen = strlen(mesbuf);
sendto(s_sock, mesbuf, sendlen, 0, (SOCKADDR*)&maddr, sizeof(maddr));
}
return 0;
}
unsigned __stdcall recvf(LPVOID arg) // recv thread function
{
SOCKADDR_IN paddr; // peer address
int namelen = sizeof(paddr);
SOCKET r_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int recvlen;
while (1)
{
char mesbuf[MAXBUF];
//recive
recvlen = recvfrom(r_sock, mesbuf, MAXBUF - 1, 0, (SOCKADDR*)&paddr, &namelen);
cout << "recv Thread" << endl;
if (recvlen == SOCKET_ERROR) {
err_display("recv error");
closesocket(r_sock);
break;
}
if (recvlen == 0)
{
cout << "normal close connection case" << endl;
closesocket(r_sock);
break;
}
mesbuf[recvlen] = '\0'; // string conversion
cout << "from : " << mesbuf << endl;
}
return 0;
}
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.
I made a server socket in C++ for Unix (TCP), that accepted only one client socket. Today, I attempted to make it accept multiple ones. For some reason, it ends up only accepting 1, and it's not receiving messages sent by the client that IS able to connect. I believe that the select function isn't working properly. FYI: I'm new to socket programming, so please understand if it's a stupid mistake.
Here's the code:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#define PORT 8080
#define MAXCLIENTS 30
int main()
{
//create a socket
int listening = socket(AF_INET, SOCK_STREAM, 0); //(returns int) - makes socket (returns what socket it is in terms of an int)
if(listening < 0) //check if we were able to make a socket!
{
std::cerr << "Can't create socket!" << std::endl;
return -1;
}
//bind the socket to an IP/Port
sockaddr_in hint{}; // This creates a structure for the ipv4 info of the socket.
hint.sin_family = AF_INET; //set the family to ipv4
hint.sin_port = htons(PORT); //set the port to the macro set above (use host-to-network-short to conver the int to the port)
hint.sin_addr.s_addr = INADDR_ANY; //set the ip to any address
if(bind(listening, (sockaddr*)&hint, sizeof(hint)) < 0) //attempt to bind socket (inticated by what number the `listening` socket is) to ip/port
{
std::cerr << "Can't bind to IP/Port" << std::endl;
return -1;
}
//mark the socket for listening
if(listen(listening, MAXCLIENTS) < 0 /*SOMAXCONN = maximum amount of connections, defined by sys/socket.h*/) //attempt to listen on the socket number indicated by `listening`
{
std::cerr << "Can't listen on the socket!" << std::endl;
return -1;
}
//FD_CLR() = Remove 1 from set
//FD_SET() = Add to set
//FD_ZERO() = Remove everything from set
//FD_ISSET() = Check if something is part of a set
fd_set master; //define the set
int max_sd;
int client_socks[MAXCLIENTS]{};
while (true)
{
FD_ZERO(&master); //make sure it's cleared
FD_SET(listening, &master); //add the listening socket (server) to the set
max_sd = listening; //max socket descriptor set to the listening socket (need this for the select func)
for (int i = 0; i < MAXCLIENTS; i++) {
if (client_socks[i] > 0) //make sure the particular socket exists
{
FD_SET(client_socks[i], &master); //add it to the set
}
if (client_socks[i] > max_sd) //if the socket is greater than our current maximum socket descriptor
{
max_sd = client_socks[i];
}
}
//wait for some action on any socket within the master fd (this will set the master fd_set to be equal to whatever socket had some action on it)
int activity = select(max_sd + 1, &master, nullptr, nullptr, nullptr);
if (activity < 0) //error!
{
std::cerr << "Error while trying to select!" << std::endl;
}
int addrlen = sizeof(hint);
if (FD_ISSET(listening, &master)) //if the select got that there was action on the listening (server) socket - most likely, a client socket is trying to connect!
{
int client_socket;
client_socket = accept(listening, (sockaddr *) &hint, &addrlen); //accept the first client "waiting to get in"
if (client_socket < 0) {
std::cerr << "Something went wrong when trying to accept a client socket!" << std::endl;
break;
}
std::cout << "New connection: " << inet_ntoa(hint.sin_addr) << " on port " << ntohs(hint.sin_port) << std::endl;
if (send(client_socket, "Welcome to the socket party!", strlen("Welcome to the socket party!"), 0) != strlen("Welcome to the socket party!")) { //greetings!
std::cerr << "Error when sending welcome message." << std::endl; //something went wrong ;(
}
for (int i = 0; i < MAXCLIENTS; i++) //for each index, set client_sock to the address of the index of client_socks, so that we can set the value of it!
{
if(client_socks[i] == 0) //if this position is null (0)
{
client_socks[i] = client_socket;
}
}
}
//else, there was action on a client socket (most likely a message is being sent!
char buffer[2048]; //we need somewhere to store clients messages!
for (int &client_sock : client_socks) //loop through the client sockets
{
if (client_sock != 0)
{
if (FD_ISSET(client_sock, &master) == 0) //check if the select got action on the particular index in the client_socks array
{
memset(&buffer, 0, sizeof(buffer)); //make sure the buffer is clear!
if (read(client_sock, &buffer, 2048) == 0) //check if nothing was recieved from the client
{
getpeername(client_sock, (sockaddr*)&hint, (socklen_t*)&addrlen) < 0; //gets networking info, based off of which socket is passed (the if statement checks for errors). In addition, it sets the values of hint to the info from the passed socket
//print that the client disconnected
std::cout << "A client has disconnected! IP: " << inet_ntoa(hint.sin_addr) << " Port: " << ntohs(hint.sin_port) << std::endl;
close(client_sock); //close the socket
client_sock = 0; //set its value in the array to 0, so that we can reuse it!
}
//else, we got message from the client
for (int &socket : client_socks)
//if (socket != client_sock)
send(socket , buffer , strlen(buffer) , 0 );
}
}
}
return 0;
}
}
Your client_socks variable must be initialised, as Igor said - just append braces: int client_socks[MAXCLIENTS]{};.
Then your for (int &client_sock : client_socks) loop doesn't ignore 0 values (which you obviously want to be a sentinel given "if(client_socks[i] == 0) //if this position is null (0)"). Inside that loop, add "if (client_sock[i] == 0) continue;. Because you try to read` from descriptor 0, it will block waiting for keyboard input.
Further, if you wanted your code to be robust, you would make the listening socket non-blocking, as it's possible for that socket to select readable, but by the time your application goes to accept from it, the client connection attempt has already been dropped: then you'd block waiting to accept another client connection attempt that might never come, and not be servicing existing clients.
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;
}
The following is the client-side code for a UDP client-server echo program :
ret_val = sendmmsg(socket_id, msgs, no_of_packets, 0);
//I send message to the server
if(ret_val == -1)
std::cerr << "Message sending failed.\n";
else{
cout << ret_val << " messages sent\n";
/************************************************************************/
char buffers[no_of_packets][packet_size + 1];
msgs = new struct mmsghdr[no_of_packets];
iovecs = new struct iovec[no_of_packets];
memset(msgs, 0, sizeof(msgs));
memset(iovecs, 0, sizeof(iovecs));
for(int i = 0;i < no_of_packets;i++){
iovecs[i].iov_base = buffers[i];
iovecs[i].iov_len = packet_size;
msgs[i].msg_hdr.msg_iov = &iovecs[i];
msgs[i].msg_hdr.msg_iovlen = 1;
}
//and receive the packet here, but the program hangs here
ret_val = recvmmsg(socket_id, msgs, no_of_packets, 0, NULL);
My program hangs here, any idea why it's happening ? The following is the server-side code which first receives and then sends successfully, but after the server sends for the first time, my client isn't able to read it as it hangs.
ret_val = recvmmsg(socket_id, msgs, no_of_packets, 0, NULL);
if(ret_val < 0){
break;
}
else{
cout << ret_val << " messages received\n";
for(int i = 0;i < ret_val;i++){
buffers[i][msgs[i].msg_len] = 0;
printf("Trip %d : %s\n", trip, buffers[i]);
}
/************************************************************************/
if(connect(socket_id, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1){
perror("connect()");
exit(EXIT_FAILURE);
}
ret_val = sendmmsg(socket_id, msgs, no_of_packets, 0);
//This send is successful, but since my client hangs,
//the server hangs as well since the 'recvmmsg' at the top gets nothing from the client
if(ret_val == -1)
std::cerr << "Message sending failed.\n";
else
cout << ret_val << " messages sent\n";
This line in the server code looks suspicious:
if(connect(socket_id, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
What is server_addr? It's certainly not the source address of any of the packets return from the prior call to recvmmsg.
Just remove the connect call.
I could write more, but is there any particular reason you are using recvmmsg and sendmmsg instead of recvfrom and sendto ?
Below is a much simpler way of implementing an echo server with a udp socket:
const int MAX_UDP_MESSAGE_SIZE = 65535
unsigned char message[MAX_UDP_MESSAGE_SIZE+1];
int rcvReslt, sndResult;
sockaddr_in addr = {};
socklen_t addrLength = sizeof(addr);
rcvResult = recvfrom(socket_id, message, MAX_UDP_MESSAGE_SIZE, 0, (sockaddr*)&addr, &addrLength);
if (rcvResult > 0)
{
message[rcvResult] = 0; // null terminate the message
printf("Trip %d : %s\n", trip, message);
// echo back
sndResult = sendto(socket_id, message, rcvResult, 0, (sockaddr*)&addr, addrLength);
}
else
{
int error_code = errno;
printf("Error: %d\n", error_code);
}
Clearly you're connected to the wrong target. You don't need to connect at all. recvfrommsg() both return the source IP:port. Just send back to the same place.