i am trying to implement a TCP server that accepts multiple client nodes. However, the control is just stuck at select() and not moving beyond that. This is my code:
#include <iostream>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(){
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(2987);
inet_pton(AF_INET, "0.0.0.0", &hint.sin_addr);
bind(server_socket, (sockaddr*)&hint, sizeof(hint));
listen(server_socket, SOMAXCONN);
fd_set master;
FD_ZERO(&master);
FD_SET(server_socket, &master);
int client_socket;
sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
while(true){
fd_set copy = master;
int socket_count = select(0, ©, nullptr, nullptr, nullptr);
cout << "Reached here!" << endl;
for(int i=0; i<socket_count; i++){
if(FD_ISSET(i, ©)){
if(i == server_socket){
client_socket = accept(server_socket, (sockaddr *) &client_addr, &client_len);
}else{
// Message
}
}
}
}
}
However, the control never moves beyond the select statement. It just remain there even after i open a connection to the server with telnet:
$ telnet 127.0.0.1 2987
Why it stuck there and how do i get the client socket with this?
Here is the manual of select.
The first parameter should not be zero, but be the highest file-descriptor that select should manage plus 1. In your case it's:
int socket_count = select(server_socket + 1, ©, nullptr, nullptr, nullptr);
Related
I'm trying to complete a simple echo server. The goal is to repeat back the message to the client. The server and client both compile.The server is binded to localhost and port 8080. The client has the address, the port, and the message. When the client goes through the program to the sendto section, it stop and waits there. My goal it to have it sent to the server, and the server to send it back.
Problem: The client is send the message and the server is receiving it correctly but the server is not able to return the message. Please help!
SERVER SIDE CODE:
#include <iostream>
#include <string.h>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8080
using namespace std;
int main() {
int serSockDes, len, readStatus;
struct sockaddr_in serAddr, cliAddr;
char buff[1024] = {0};
char msg[] = "Hello to you too!!!\n";
//creating a new server socket
if((serSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation error...\n");
exit(-1);
}
//binding the port to ip and port
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(PORT);
serAddr.sin_addr.s_addr = INADDR_ANY;
if((bind(serSockDes, (struct sockaddr*)&serAddr, sizeof(serAddr))) < 0) {
perror("binding error...\n");
exit(-1);
}
readStatus = recvfrom(serSockDes, buff, 1024, 0, (struct sockaddr*)&cliAddr, (socklen_t*)&len);
buff[readStatus] = '\0';
cout<<buff;
cout<<len;
sendto(serSockDes, msg, strlen(msg), 0, (struct sockaddr*)&cliAddr, len);
return 0;
}
CLIENT SIDE CODE:
#include <iostream>
#include <fstream>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8080
using namespace std;
int main(int argc, char** argv) {
int cliSockDes, readStatus, len;
struct sockaddr_in serAddr;
char msg[] = "Hello!!!\n";
char buff[1024] = {0};
//create a socket
if((cliSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation error...\n");
exit(-1);
}
//server socket address
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(PORT);
serAddr.sin_addr.s_addr = INADDR_ANY;
sendto(cliSockDes, msg, strlen(msg), 0, (struct sockaddr*)&serAddr, sizeof(serAddr));
readStatus = recvfrom(cliSockDes, buff, 1024, 0, (struct sockaddr*)&serAddr, (socklen_t*)&len);
buff[readStatus] = '\0';
cout<<buff;
return 0;
}
The client is trying to send its message to INADDR_ANY, which is wrong. It needs to send to a specific IP address instead. The server can listen to all of its local IP addresses using INADDR_ANY, that is fine, but the IP address that the client sends to must be one that the server listens on (or, if the client and server are on different network segments, the client must send to an IP that reaches the server's router, which then must forward the message to an IP that the server is listening on).
Also, your calls to recvfrom() and sendto() on both ends are lacking adequate error handling. In particular, the addrlen parameter of recvfrom() specifies the max size of the sockaddr buffer upon input, and upon output returns the actual size of the peer address stored in the sockaddr. But you are not initializing the len variable that you pass in as the addrlen, so recvfrom() is likely to fail with an error that you do not handle.
Try something more like this instead:
Server:
#include <iostream>
#include <string.h>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
#define PORT 8080
int main() {
int serSockDes, readStatus;
struct sockaddr_in serAddr, cliAddr;
socklen_t cliAddrLen;
char buff[1024] = {0};
char msg[] = "Hello to you too!!!\n";
//creating a new server socket
if ((serSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation error...\n");
exit(-1);
}
//binding the port to ip and port
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(PORT);
serAddr.sin_addr.s_addr = INADDR_ANY;
if ((bind(serSockDes, (struct sockaddr*)&serAddr, sizeof(serAddr))) < 0) {
perror("binding error...\n");
close(serSockDes);
exit(-1);
}
cliAddrLen = sizeof(cliAddr);
readStatus = recvfrom(serSockDes, buff, 1024, 0, (struct sockaddr*)&cliAddr, &cliAddrLen);
if (readStatus < 0) {
perror("reading error...\n");
close(serSockDes);
exit(-1);
}
cout.write(buff, readStatus);
cout << endl;
if (sendto(serSockDes, msg, strlen(msg), 0, (struct sockaddr*)&cliAddr, cliAddrLen)) < 0) {
perror("sending error...\n");
close(serSockDes);
exit(-1);
}
close(serSockDes);
return 0;
}
Client:
#include <iostream>
#include <fstream>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
#define PORT 8080
int main(int argc, char** argv) {
int cliSockDes, readStatus;
struct sockaddr_in serAddr;
socklen_t serAddrLen;
char msg[] = "Hello!!!\n";
char buff[1024] = {0};
//create a socket
if ((cliSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation error...\n");
exit(-1);
}
//server socket address
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(PORT);
serAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (sendto(cliSockDes, msg, strlen(msg), 0, (struct sockaddr*)&serAddr, sizeof(serAddr)) < 0) {
perror("sending error...\n");
close(cliSockDes);
exit(-1);
}
serAddrLen = sizeof(serAddr);
readStatus = recvfrom(cliSockDes, buff, 1024, 0, (struct sockaddr*)&serAddr, &serAddrLen);
if (readStatus < 0) {
perror("reading error...\n");
close(cliSockDes);
exit(-1);
}
cout.write(buff, readStatus);
cout << endl;
close(cliSockDes);
return 0;
}
I have an odd issue. I have been attempting to learn to use network sockets in C/C++, and I'm currently having trouble understanding why my server code does not work. I have followed a tutorial's code almost to a T, and although the example code functions fine, my code does not. I can telnet localhost 5000 to the example program just fine, but telnet simply gives me connection refused when I test my server code.
Here is my code:
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
// declare int socket descriptor and call socket() to assign to it
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
perror("Error on socket creation.");
// declare address struct
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof serv_addr);
// set values in address struct
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
// need to cast sockaddr_in to sockaddr struct
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof serv_addr);
// listen on socket with num of allowed connections
if (listen(sockfd, 10) == -1)
perror("Error on listen");
int connfd;
char msg [1025];
memset(msg, 0, sizeof msg);
while (1)
{
connfd = accept(sockfd, (struct sockaddr*)NULL, NULL);
strcpy(msg, "Message lol");
write(connfd, msg, strlen(msg));
close(connfd);
sleep(1);
}
return 0;
}
This is example that functions as expected: https://pastebin.com/CG9ZWz49
And this is the tutorial I got the example from:
https://www.codeproject.com/articles/586000/networking-and-socket-programming-tutorial-in-c
Any help would be greatly appreciated. Thanks.
I am trying to make a C++ server-client communication program. Currently, both server and client are on localhost.
When I run server.cpp, it waits at "Listening...", as expected, and does not continue further till I don't run client.cpp. When client is run, server prints "Connected" and both server and client end.
But when I run client.cpp only, it prints "Connecting..." and then "Connected" after one second, even if server.cpp is not running, and specified port is not open.
I have triple checked both codes, tried them many times, also checked open ports before running only client, changed port many times, but nothing worked. Why does client say "Connected" even when server is not running?
server.cpp:
#include <cstdio>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#define PORT 11056
int main(int argc, char** argv) {
int sock = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
if (sock == -1) {
printf("E) Socket creation\n");
return 1;
}
struct sockaddr_in server, client;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = PORT;
server.sin_family = AF_INET;
int binded = bind(sock, (struct sockaddr *)&server, sizeof(server));
if (binded == -1) {
printf("E) Binding\n");
return 1;
}
printf("4) Listening...\n");
listen(sock, 5);
int new_sock = accept(sock, (struct sockaddr *)&client, (socklen_t *)sizeof(client));
printf("5) Connected\n");
shutdown(sock, SHUT_RDWR);
close(new_sock);
close(sock);
printf("EXIT\n");
return 0;
}
client.cpp
#include <cstdio>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 11056
int main(int argc, char** argv) {
int sock = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
if(sock == -1) {
printf("Error creating socket\n");
return 1;
}
struct sockaddr_in client;
client.sin_port = PORT;
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr("127.0.0.1");
printf("3) Connecting...\n");
connect(sock, (struct sockaddr *)&client, sizeof(client));
printf("4) Connected\n");
close(sock);
printf("EXIT");
return 0;
}
I am trying to get a very basic hello world UDP sender and UDP multicast listener to work. I have a PC but have a virtual machine with the Linux OS CentOS. It has no problems connecting to the internet. The sender and listener are two separate programs, Eclipse is my environment.
The Sender...
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define UDP_PORT 5403
#define UDP_GROUP "225.0.0.1" // 127.0.0.1
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd;
struct ip_mreq mreq;
char *message="Hello, World!";
int message_size = strlen(message) + 1;
// Create a UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
perror("socket(...) ");
return -1;
}
// allow multiple sockets to use the same PORT number
u_int reuse_port = 1;
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &reuse_port, sizeof(reuse_port)) < 0)
{
perror("setsockopt(...) ");
return -1;
}
// set up destination address
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(UDP_GROUP);
addr.sin_port = htons(UDP_PORT);
printf("Begin sendto(...) infinite loop\n");
while (true)
{
printf("Sending message: %s, of size: %d\n", message, message_size);
if (sendto(fd, message, message_size, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("sendto(...): ");
return -1;
}
// printf("message sent: %s\n", message);
sleep(1);
}
return 1;
}
The Listener...
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define UDP_PORT 5403
#define UDP_GROUP "225.0.0.1"
#define MAX_BUFFER_SIZE 256
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes;
socklen_t addrlen;
struct ip_mreq mreq;
char msgbuf[MAX_BUFFER_SIZE];
u_int reuse_port = 1;
// Create a socket
fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd < 0)
{
perror("create socket failed");
return -1;
}
// allow multiple sockets to use the same PORT number
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_port, sizeof(reuse_port)) < 0)
{
perror("Reusing port number failed");
return -1;
}
// set up destination address
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(UDP_PORT);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
// Set the recvfrom timeout after 1 s
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
perror("Error setting recvfrom timeout\n");
return -1;
}
// use setsockopt() to request that the kernel join a multicast group
mreq.imr_multiaddr.s_addr = inet_addr(UDP_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return -1;
}
addrlen = sizeof(addr);
printf("Begin recvfrom(...) infinite loop\n");
while (true)
{
nbytes = recvfrom(fd, msgbuf, MAX_BUFFER_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
if (nbytes < 0)
{
printf("recvfrom timeout\n");
}
else
{
printf("message received: %s\n", msgbuf);
}
}
return 1;
}
Every second, the sender program printf's "Sending message: Hello, World!, of size: 14" and every two seconds the receiver printf's "recvfrom timeout". I have set Wireshark to look at UDP traffic and I definitely see the sento data. The recvfrom is not getting any data. I have tried using many different Group IP's from 255.0.0.0 to 239.255.255.255, no change. I have tried many different ports, no change. Is their a special setup I need to do on my network card? I'm not sure what else to do. Small edit, the recvfrom and sendto message should not have "&".
I have a very simple recvfrom() command that works fine - so long as it is not called in "another" thread.
I would post more code, but there is quite a bit of it, so hopefully I can filter out the relevant bits:
First we have the global variable: SOCKET Socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);.
So long as threads are not involved, this works fine:
char message[_max_message_];
struct sockaddr_in* from;
int r;
int SenderAddrSize = sizeof (struct sockaddr);
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n",r,WSAGetLastError);
Now I have identical code called behind a thread, like this:
pthread_create(&listener, NULL, listenloop, &Socket);
(The code basically ignores &socket.)
The first recvfrom() to execute, from the called thread, returns -1, but the recvfrom() from the "original" thread (where the networking was setup) successfully fills message with the, well, message from the server.
So kind as to tell me what I'm doing wrong?
EDIT: I hate to throw more than a dozen lines at strangers kind enough to help me, but I don't think I'm gonna get an answer if I don't. So, here is the kit and kaboodle, edited slightly:
#include <iostream>
//#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <conio.h>
using namespace std;
#include <string>
//One thread shall listen continually for responses from the server.
/*The other thread shall listen continually for user input, and fire off user input at the local
client to the server...*/
//#ifdef _WINDOWS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
inline int randport()
{
return (50000 % rand() + 1000);
}
#define _serverip_ "***.***.***.***"
#define _welcome_ "Welcome,Wagon!"
#define _randomport_ 64000%rand()+100
#define _max_message_ 100
void *listenloop(void *arg)
{
//SOCKET* listener = (SOCKET)arg;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
int r;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
//while (1){
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Thread Bytes recieved: %i\nThread Error Code: %i\n", r,
WSAGetLastError);
return NULL ;
//}
return NULL ;
}
int main()
{
string user, pass, login;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
int port;
cout << "Welcome!"
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
fflush(stdin); //As long as we compile with GCC Behavoir should be consistant
//TRY NOT TO SEND PLAINTEXT PASSWORDS LIKE THIS! IT MAY MAKE YOUR USERS VULNERABLE! DONE FOR SAKE OF SIMPLICITY HERE!
cout << "\n\nPlease enter the username you registered with:";
getline(cin, user);
cout << "\nPlease enter your password, my good sir: ";
getline(cin, pass);
struct hostent *host;
host = gethostbyaddr(_serverip_, strlen(_serverip_), AF_INET);
if (host == NULL )
{
cout << "\n\n UNABLE TO CONNECT TO SERVER. QUITTING. ";
return -1;
}
short errorcount = 3;
int socketfeedback;
///Put the address for the server on the "evelope"
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(_serverip_);
///Sign the letter...
int myport = _randomport_;
int code;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("localhost");
service.sin_port = htons(myport);
//bind(Socket, (SOCKADDR *) &service, sizeof(service));
//Start a thread, listening for that server
while ((errorcount))
{
code = bind(Socket, (SOCKADDR *) &service, sizeof(service));
if (code)
break;
else
return -5;
errorcount--;
myport = _randomport_;
service.sin_port = htons(myport);
}
login = user + ',' + pass;
if (!errorcount)
{
cout << "\n\nMiserable failure. Last Known Error Code: " << code;
return -1;
}
///Begin the listen loop!!
pthread_t listener;
pthread_create(&listener, NULL, listenloop, &Socket);
struct sockaddr result;
sendto(Socket, login.c_str(), strlen(login.c_str()), 0,
(struct sockaddr *) &SockAddr, sizeof(SockAddr));
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
int r;
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n", r, WSAGetLastError);
//SOCKET listener=(SOCKET)arg;
WSACleanup();
return 0;
}
Why do you use global Socket? And why are you declaring another Socket in main? You should better use the socket passed in pthread_create (just cast args in listenloop to SOCKET *). Global variables in multithreaded are a really bad idea (you need synchronization mechanism). And initialize your struct sockaddr_in from with zeros (for e.g. with memset, or just do as alk said : struct sockaddr_in from = {0}).
And also you are reading from one socket in two different threads without any kind of synchronization. This is bound to cause many errors.
And also I see a problem with WSACleanup and recvfrom in other thread. You don't know in what order will these two run (so you can also get WSACleanup before you can recvfrom in other thread).You can use pthread_join to wait for other thread to finish and then do WSACleanup.
This is too long for a comment.
The code as posted would not work at all, due to declaring:
struct sockaddr_in* from;
and then using from like this:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
You are paasing the address of the address of struct sockaddr_in instead of only its address.
Is shall be:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
However if doing so you are missing to allocate memory to from.
So propably
struct sockaddr_in* from;
is a typo and should have read:
struct sockaddr_in from = {0};
?