I am using sockets in order to synchronize several remote processes.
The idea is that a process creates a pthread which manages the server side, just like that:
void *listener(void * in) {
int sockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = *((int *) in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
int option = 1;
setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof (option));
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR on binding");
if (listen(sockfd, n) < 0)
error("ERROR when listening");
clilen = sizeof (cli_addr);
int cnt = 0;
while (cnt < n) {
int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
}
cnt++;
}
close(sockfd);
return 0;
}
Meanwhile, the other processes would execute:
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(_managementHost); //managementHost);
if (server == NULL)
error("ERROR, no such host\n");
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR connection");
close(sockfd);
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
I guess that is because the accepts may not be ready... In fact, I have read that it could happen, but I have not found my specific case.
Could anyone shed light on the matter?
A possible solution that occurs to me, is to create a thread for each accept, but I would prefer to avoid it.
Thank you.
EDIT: corrected double initialization of socket in the server. Thanks to #Remy Lebeau.
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
A listening TCP socket has a backlog of pending connections. The 2nd parameter of listen() specifies how many connections are allowed to be in the backlog queue before they are accepted. If a new client tries to connect when the backlog is full, the client is refused. There is nothing the client or server can do about that. It is the client's responsibility to detect the error and re-connect at a later time.
Your listener() is accepting clients until it reaches a designated number of connections, but you are also using that same number for the listen backlog queue size. The number of active connections and the number of pending connections are two different things. If you are expecting a lot of clients to connect at the same time, you need a large backlog size to avoid the refusal errors. But that backlog should be sized proportional to the traffic you are expecting. If you have 1000 clients, but they connect only 20 at a time, you would set the backlog to, say, 25, not 1000.
Your listener() has some other logic bugs. It is calling socket() twice and saving the two sockets to the same sockfd variable, so it is leaking the first socket. You need to remove the second call to socket() (the one just before setsockopt()). You are also leaking the sockets that accept() returns. You need to close() an accepted socket after you are doing using it.
Just make your server concurrent by calling fork to spawn a child for each client. Easiest way to do it, IMO. Avoids threading and will stop the connection refused errors.
EDIT: You could also look into pre-forking your server. You'd have to research how you want to handle locking around accept, though (if you're locking at all).
Related
I checked my code but I don't know why the program can't bind the socket.
I tried many ip and ports(even 127.0.0.1) but it still don't works...
Here is the code I'm using :
//error message
void error (const char *msg)
{
perror(msg);
exit(1);
}
int main ()
{
int sock, cli_sock, portno;
char buffer[1024];
char response[18432];
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len;
//creating socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
error("Error opening socket");
bzero ((char *) &serv_addr, sizeof(serv_addr));
//giving port number
portno = 50005;
//giving ip address
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(portno);
//bind socket
if(bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0)
error("Binding failed.");
//listen
listen(sock, 5);
cli_len = sizeof(cli_addr);
//accept
cli_sock = accept(sock, (struct sockaddr *) &cli_addr, &cli_len);
if(cli_sock != 0)
error("Error on accepting");
}
(This is just the socket part of the server code and just for more info, my client version is for Windows and my server version is for Linux)
This is my output when I run the program :
Binding failed.: Cannot assign requested address
For TCP the setup for client and server were:
Server:
socket (create listening socket)
bind (listening socker to local address:port)
listen (make listening socket actually listen)
(accept loop header)
accept (have listening socket wait for incoming connections; returns accepted socket on succesful connection)
read/write (from/to accepted socket!)
shutdown (accepted socket; optional)
close (accepted socket)
(loop footer)
shutdown (listening socket; optional)
close (listening socket)
Client:
socket
bind (to local address:port, optional and uncommon)
connect (to remote address:port, those the server was bound to)
read/write
shutdown (optional)
close
I wrote a program to play tick tack toe across a network (or potentially the internet). I wrote this using C.
The program works just fine when I run the host and client on the same machine. I cannot, however, establish a connection when it is running on two different machines.
I'm using Ubuntu 18.04 LTS on both computers. I don't see why this would matter, but one is connected to the router via ethernet. The other is connected to the network wirelessly. ufw verbose shows that the firewall is inactive on both computers.
Things that I've already tried:
Adding server name to the host in /ect/hosts instead of typing
the ip address into the program argument (works both ways on local
machine, does not work either way across the network).
Adding firewall exception to the router firewall.
Port forwarding the port that I'm using (5001) on my router.
nmap to the ip of the computer running the host shows that port 5001/tcp is open with service "commplex-link"
Can telnet into the host from remote computer across the network.
void network_host(void) {
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
struct game *main_game = createboard();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("On opening socket ERROR: \n");
exit(1);
}
memset(&serv_addr, 0, sizeof serv_addr );
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof serv_addr ) < 0 ) {
perror("On socket binding ERROR: \n");
exit(1);
}
printf("Waiting for opponent . . .\n");
listen(sockfd, 1);
clilen = sizeof cli_addr;
memset(&cli_addr, 0, clilen);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("On accepting connection ERROR: \n");
exit(1);
}
printf("Opponent connected!\n");
while (main_game->play) {
printboard(main_game);
entermove(main_game, GAME_HOST, newsockfd);
checkwin(main_game);
}
}
void network_client(char *host_name) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
struct game *main_game = createboard();
portno = 5001;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Error opening socket");
exit(1);
}
server = gethostbyname(host_name);
if (server == NULL) {
fprintf(stderr, "Error, no such host.\n");
exit(0);
}
memset((char *) &serv_addr, 0, sizeof serv_addr);
serv_addr.sin_family = AF_INET;
memcpy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Error connecting.\n");
exit(1);
}
while (main_game->play) {
printboard(main_game);
entermove(main_game, GAME_CLIENT, sockfd);
checkwin(main_game);
}
}
Since this program will work when connected to localhost, nmap shows the port open remotely, and I can telnet into the program remotely, I can't at all figure out where to go next.
It would seem to me that its not a coding error since it works locally, but since I can telnet into the program then it seems that it should't be a networking error.
I'm willing to backtrack through these steps (maybe some of them I've only done half right). But also willing to accept other possible ideas.
This line is where your problem is
memcpy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
memcpy is defined as taking a destination, source and size...so you're copying things the wrong way around as server is where the address is. Swap things around and it should work just fine...
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
You don't need to cast anything either as firstly those two arguments to memcpy are meant to be void * not char * and secondly, pointers convert to void * automatically
I am writing a custom HTTP server in C for my OpenWrt router. It makes use of the uclibc library. I am only using one static buffer which I am very careful not to overflow, and no multi-threading is involved. It doesn't contain any complex data structures, and what it does is that:
it listen() s on the socket
reads the request after accept() ing
gets an html page by sending an http request to a predefined remote server (not a proxy)
sends the result through the accepted connection, and closes both.
The program would just stop running after some time, (it can be on receiving the first request, or after working under heavy strain for more that 2 hours). I am getting no error messages through the console, or anything, the program just stops. I have watched it and, as expected it doesn't consume more and more memory as it runs...
Is it possible that the kernel stops it if it thinks its abusing the CPU? How do I overcome that?
Are there some quirks to watch for in socket programming in C that are known to cause such crashes?
Can the stability issues be caused by using the Barrier Bracker (bleeding edge) branch of OpenWrt? Although the router itself never stops working...
Where do I start to look for the source of the problem?
Ok, first, I would like to thank everybody for helping. After writing a lot of netcat testers, I have pinpointed the problem. The program would crash - end without a single error message, if the connection is closed by the client before the last write or read occurs.
The write or read would raise a SIGPIPE signal which by default crashed the program if not handled manually... More info here: How to prevent SIGPIPE or prevent the server from ending?
This seems to be similar to what your trying to do,
as shown on http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html
Is this socket setup the same/similar to what your performing in your code?
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
return 0;
}
My goal is set up a wireless peer to peer networking using socket. Server and Client model. The code for Server is such.
Server.c
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
Client.c
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return 0;
My questions are
1)What's the hostname I should set in the server.c in one of the Mobile Phone? Or what should the hostname the client (another one of the Mobile Phone) expect to see.
2)what should I use for port number for TCP communication between two Mobile devices. ANything above 2000? Let say I have one iPhone and one Android and I am trying to setup peer to peer wireless networking between the two.
For your second question. YOu will have to use a port number that is known to both devices, otherwise the client would not know the port number on which to invoke connect() and thus, establish the connection with the server. Now, first 1024 are reserved but so are some of the ports beyond 1024! You can find hte list here: http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml . The largest numebr I see is 49151, so I would start with a random value between 49151 and 64K. Lastly, since TCP layer is standard, picking a common port number should not matter if you use an iPhone with Android or any other TCP-aware device.
Your first question is tricky. The more basic question is how do you discover the peer? May be, the peers can broadcast messages once in while to help others discover them -- broadcast messages are UDP messages and once can know the sender and the port number from received UDP messages. Next, the TCP client can use that and then connect to the peer. In fact, you can also have the host send a broadcast message (as long as you fix the port number for your app) and let the clients reply. Needless to say, you dont want to send these discovery floods too often.
Answering your first question the hostname can be anything which is registered with DNS. Specifying an IP address will also do the trick but make sure its a Public IP.
The Port number can be any number that the server machine is not bound to. It is recommended to have above 2000 but not necessary.
One thing to keep in mind is in socket programming we are dealing with sockets which are either UDP or TCP (L4) (unless you are talking about RAW sockets). So this means we are not worried about L2 (whether it is wired or wireless). This implies that your code will work the same for both wireless, wired, and hybrid.
I have an application written in C that is a server and a client at the same time. What I do is the following:
sock = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&server, length);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(MYPORT);
char broadcast = '1';
int broadcastlen = sizeof(broadcast);
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, &broadcastlen) < 0) {
close(sock);
error("Error in setting broadcast option");
}
if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) {
close(sock);
error("Error in BINDING");
}
bzero(&sender, length);
bcast.sin_family = AF_INET;
bcast.sin_addr.s_addr = NBCAST; // NBCAST is the broadcast address of the subnet
bcast.sin_port = htons(MYPORT);
if (sendto(sock, dateQuery, strlen(dateQuery) + 1, 0, (struct sockaddr*)&bcast, sizeof(bcast)) < 0) {
close(sock);
error("ERROR in sending");
}
Up to this point everything works well. But I start a thread with the sock parameter to listen to, and do the following:
int len = sizeof(struct sockaddr_in);
struct sockaddr_in sender_addr;
recfrom(sock, recvbuff, recvbufflen, 0, (struct sockaddr*) &sender_addr, &len);
And it blocks there forever. I tried to make it work from different PCs, but it doesn't seem to work, because the thread is blocked due to recvfrom(). Can anyone tell me what is wrong with my code?
Thanks
EDIT: if my code is broken, could you please suggest a way to solve this? So, my task is to implement an application in C that is a server and a client at the same time. I send a broadcast message every 3 seconds, and I have to answer to that broadcast message with the system time.
So far this is the idea I came up with, of course I did not answer to that broadcast message since I couldn't even read it.
I just solved the problem. The code works perfectly, I just had to disable the firewall. But I don't know exactly how did this help me. Any way, thanks for the answers and comments.
Perhaps, you have to make the socket non-blocking?
Try:
u_long iMode = 1;
ioctlsocket(sock, FIONBIO, &iMode);