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.
Related
My goal is to create a user-server connection. Most importantly I'm not willing to use threads.
For now, I want it to work as a simple chat. I believe The issue is that It goes from one user to another in a loop waiting for their getline input, so technically only one user can send a message at a time. What I wish is that my code could handle multiple messages from one user continuously, not having to wait for all other users to send a message
That's the running loop inside the server:
while (running)
{
fd_set copy = master;
// See who's talking to us
int socketCount = select(0, ©, nullptr, nullptr, nullptr);
// Loop through all the current connections / potential connect
for (int i = 0; i < socketCount; i++)
{
// Makes things easy for us doing this assignment
SOCKET sock = copy.fd_array[i];
// Is it an inbound communication?
if (sock == listening)
{
// Accept a new connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientsocket = accept(listening, (sockaddr*)&client, &clientSize);
// Add the new connection to the list of connected clients
FD_SET(clientsocket, &master);
// Send a welcome message to the connected client
string welcomeMsg = "Welcome to the Awesome Chat Server!\r\n";
send(clientsocket, welcomeMsg.c_str(), welcomeMsg.size() + 1, 0);
}
else // It's an inbound message
{
char buf[4096];
ZeroMemory(buf, 4096);
// Receive message
int bytesIn = recv(sock, buf, 4096, 0);
if (bytesIn <= 0)
{
// Drop the client
closesocket(sock);
FD_CLR(sock, &master);
}
else
{
// Send message to other clients, and definiately NOT the listening socket
for (int i = 0; i < master.fd_count; i++)
{
SOCKET outSock = master.fd_array[i];
if (outSock != listening && outSock != sock)
{
ostringstream ss;
ss << "SOCKET #" << sock << ": " << buf << "\r\n";
string strOut = ss.str();
send(outSock, strOut.c_str(), strOut.size() + 1, 0);
}
}
}
}
}
}
I belive this code should work, the issue is in my client code:
char buf[4096];
string userInput;
do
{
// Prompt the user for some text
cout << "> ";
getline(cin, userInput); //THATS THE ISSUE, IT WAITS FOR GETLINE
if (userInput.size() > 0) // Make sure the user has typed in something
{
// Send the text
int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
if (sendResult != SOCKET_ERROR)
{
// Wait for response
ZeroMemory(buf, 4096);
int bytesReceived = recv(sock, buf, 4096, 0);
if (bytesReceived > 0)
{
// Echo response to console
cout << "SERVER> " << string(buf, 0, bytesReceived) << endl;
}
}
}
} while (userInput.size() > 0);
My question is if its really caused by getline and if so, how can it be fixed?
The answer to your question is "yes," but with a big proviso: a properly designed server shouldn't care what the client is doing. You might want to look into select() or, if you anticipate a large user community, poll(). You don't want a multi-user server to depend on/wait for a single client.
I am new in Socket Programming. I am trying to create a Application that uses Sockets for Communication.
I have doubt in the Receive function because sometime it just hangs in recvfrom function.
I am using select function for polling. It works when Camera is connected but If I remove Camera it doesn't show the Error Message.
My Code for Polling:
FD_ZERO(&m_readFds);
FD_SET(Sock, &m_readFds);
m_timeInterval.tv_usec = 30; //30 Microseconds for Polling
m_socketLength = sizeof(m_cameraInfo);
m_lastBlockId = -1;
while (m_acquiringThreadStatus)
{
FD_CLR(Sock, &m_readFds);
FD_SET(Sock, &m_readFds);
m_receivingStatus = select(Sock + 1, &m_readFds, NULL, NULL, &m_timeInterval);
if (m_receivingStatus < 0)
{
std::cout << "No Data to Receive"<<std::endl;
}
else
{
if ((m_receivedBytes = recvfrom(Sock, m_packetBuffer, RECEIVING_BUFFER_SIZE, 0, (struct sockaddr*)&m_cameraInfo, &m_socketLength)) == SOCKET_ERROR)
{
std::cout << "ERROR" << std::endl;
}
else
{
std::cout<<"Data Received"<<std::endl;
}
}
}
An one more question is that when I continously printing the Data Received Statement after sometime It stop. So how can I increase the size of Socket Receiving Buffer.
Thanks in Advance
Edit
SOCKET m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(m_sock == INVALID_SOCKET)
{
// Error
}
else
{
//In the else part bind the socket
}
If you read select()'s documentation, you would see that select() returns -1 on error, 0 on timeout, and > 0 on requested event(s). However, that is not how you are treating the return value. You are treating -1 as timeout and >= 0 as data events. So, you end up calling recvfrom() when there is nothing available to read. If the socket is in blocking mode (its default mode), recvfrom() will block the calling thread until data is actually available.
Try this instead:
m_lastBlockId = -1;
while (m_acquiringThreadStatus)
{
FD_ZERO(&m_readFds);
FD_SET(Sock, &m_readFds);
m_timeInterval.tv_sec = 0;
m_timeInterval.tv_usec = 30; //30 Microseconds for Polling
m_receivingStatus = select(Sock + 1, &m_readFds, NULL, NULL, &m_timeInterval);
if (m_receivingStatus == SOCKET_ERROR)
{
std::cout << "ERROR" << std::endl;
break;
}
if (m_receivingStatus == 0)
{
std::cout << "No Data to Receive" << std::endl;
continue;
}
m_socketLength = sizeof(m_cameraInfo);
if ((m_receivedBytes = recvfrom(Sock, m_packetBuffer, RECEIVING_BUFFER_SIZE, 0, (struct sockaddr*)&m_cameraInfo, &m_socketLength)) == SOCKET_ERROR)
{
std::cout << "ERROR" << std::endl;
break;
}
std::cout << "Data Received" << std::endl;
}
As for the size of the socket's receive buffer, you can set it via setsockopt() using the SO_RCVBUF option, eg:
int bufsize = ...;
setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(bufsize));
I have attached the code below, the title says it all. I am able to receive one message and then all other messages sent after the first don't get sent or arent read in.
Client, send_msg is called multiple times and cppClientSocket is the constructor that sets up the connection.
void cppClientSocket::send_msg(const char msg[], int size){
sendto(sockfd ,msg, size , 0, (struct sockaddr *)&serv, sizeof(serv));
}
cppClientSocket::cppClientSocket(int port){
sockfd = socket(AF_INET,SOCK_DGRAM,0);
serv.sin_family = AF_INET;
serv.sin_port = htons(port);
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
};
Server, cppServerSocket is used to construct the other side of the UDP socket. Retrieve is called continuously from another class (within a while loop).
cppServerSocket::cppServerSocket(int port){
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd<0){
std::cout << "AN error occured when creating the socket" << std::endl;
return;
}
addrlen = sizeof(remaddr); /* length of addresses */
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
//set to udp
myaddr.sin_family = AF_INET;
//host to network - long : convert a number into a 32-bit network representation.
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
//host to network - short : convert a number into a 16-bit network representation.
myaddr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return;
}
}
std::string cppServerSocket::retrieve(){
int count = recvfrom(fd, buf, BUFSIZE-1, 0, (struct sockaddr *)&remaddr, &addrlen);
if(!displayedError && count < 0){
std::cout << "An Error occured: " << strerror(errno) << std::endl;
displayedError = true;
return "";
}
if (count >= 0){
printf("received message: \"%s\"\n", buf);
std::string rcv(buf,count);
return rcv;
}
}
Appreciate the help!
UPDATE
If I modify the retrieve so that it acts like a server that will simply print every message it recieves, it works fine without error...
std::string cppServerSocket::retrieve(){
for(;;){
int count = recvfrom(fd, buf, BUFSIZE-1, 0, (struct sockaddr *)&remaddr, &addrlen);
if(!displayedError && count < 0){
std::cout << "An Error occured: " << strerror(errno) << std::endl;
displayedError = true;
//return "";
}else if (count >= 0){
printf("received message: \"%s\"\n", buf);
std::string rcv(buf,count);
//return rcv;
}
}
return "";
}
Below added the code that was used to call the original retrieve() method.
void check_socket(cppServerSocket css){
string temp;
temp.append(css.retrieve());
if(temp.size()>0){
std::cout << temp << std::endl; //for debugging
debug.push_back(temp);
debug.pop_front();
}
}
Below is the code inside of main that calls the check_socket() method
//code inside of main
cppServerSocket css(3000);
for(int i=0; i< test_time; i++){
printScreen(test_devices, test_dev_status, false);
t = clock();
while(clock() - t < CLOCKS_PER_SEC){
check_socket(css);
}
}
GOT IT!!!
The problem was in check_socket(cppServerSocket css), because I was not passing by reference the descructor of my cppServerSocket was getting called, and in that destructor I had specified that the socket should close. So after the first message was recieved the socked would be closed. To fix this i passed cppServerSocket by reference
void check_socket(cppServerSocket &css){
string temp;
temp.append(css.retrieve());
if(temp.size()>0){
std::cout << temp << std::endl; //for debugging
debug.push_back(temp);
debug.pop_front();
}
}
Thanks to all for the help!
I am trying to implement client-server communication via sockets. The main tasks are:
Sending commands from clients to server
Sending data from server to clients
Sending data from clients to server
Commands should come via port1, data via port2.
I got it working without without multi-threading but I have some problems with understanding how do I need to handle sockets.
Current scenario:
1.Server starts (socket, bind, listen for both command and info sockets) and goes for infinite loop with this function:
void FTPServer::waitForConnection()
{
sockaddr_in client;
int clientsize = sizeof(client);
SOCKET clientSocket = accept(_infoSocket, (struct sockaddr*)&client, &clientsize);
if (clientSocket == INVALID_SOCKET)
{
cout << " Accept Info Error" << endl;
}
else
{
cout << " Accept Info OK" << endl;
char* buff = new char[CHUNK_SIZE];
string fullRequest;
int rc = recv(clientSocket, buff, CHUNK_SIZE, 0);
if (rc == SOCKET_ERROR)
{
cout << " Recieve Info Error" << endl;
}
else
{
buff[rc] = NULL;
fullRequest.append(buff);
cout << " Recieve Info OK" <<endl;
if (executeCommand(fullRequest, clientSocket))
{
logOperation(client, fullRequest.c_str());
}
}
delete buff;
}
}
2.Client starts (socket, connect), creates 2 sockets on same ports, waits for user input.
3.User types "LIST", clients checks that it's a valid command and sends it.
bool FTPClient::sendToServer(string data, const bool verbose)
{
int n = 0;
while (data.size() > CHUNK_SIZE)
{
string s = data.substr(CHUNK_SIZE).c_str();
n += send(_infoSocket, data.substr(CHUNK_SIZE).c_str(), CHUNK_SIZE, 0);
data = data.substr(CHUNK_SIZE+1);
}
n+=send(_infoSocket, data.c_str(), data.size(), 0);
cout<<n<<endl;
if(n<0)
{
cout<<"Error: sending"<<endl;
return 0;
}
if (verbose)
cout<<"Send "<<n<<" bytes"<<endl;
return true;
}
4.Servers receives it, accepts on _dataSocket and sends the list of available files.
5.Client receives the list:
string FTPClient::getDataFromServer(const bool verbose)
{
char data[CHUNK_SIZE];
int size = recv(_dataSocket, data, strlen(data), 0);
if (size > 0)
{
int n = 0;
string res;
while (size > CHUNK_SIZE)
{
int buff = recv(_dataSocket, data, CHUNK_SIZE, 0);
res.append(data);
size -= buff;
n += buff;
}
n+= recv(_dataSocket, data, CHUNK_SIZE, 0);
res.append(data);
if (verbose)
cout<<"Recevied "<<n<<" bytes"<<endl;
res.resize(n);
return res;
}
else
{
return "";
}
}
Till this, it works. But if try to execute same command again, I got nothing.
I think, problem is that for each connect we need an accept on server side.
In main loop server gets only one connect from client. Is closing client command socket and reconnecting it on every request only option here? Any other advices (except for "Google it") are highly appreciated.
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.