I have a server-client system (concurrent server). I have different clients on different machines. I am trying to send a notification to particular clients. However, I have a problem as the clients all have the same socket descriptor. On both computers, the clients have a socket descriptor of 3 and at the server a sd of 5. Can someone please tell me how I can identify these different clients and why is this happening?
int main(int argc, char *argv[]) {
pid_t pid;
int buff_size = 1024;
char buff[buff_size];
int listen_fd, client_conn;
struct sockaddr_in serv_addr;
int server_port = 5001;
char remote_file[255];
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("Socket cannot be opened");
exit(1);
}
/*Turning off address checking in order to allow port numbers to be
reused before the TIME_WAIT. Otherwise it will not be possible to bind
in a very short time after the server has been shut down*/
int on = 1;
int status = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *) &on, sizeof(on));
if (status == -1) {
perror("Failed to Reuse Address on Binding");
}
// Initialise socket structure
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; // Accept connections from any address
serv_addr.sin_port = htons(server_port);
// Bind the host address
if (bind(listen_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
< 0) {
perror("ERROR on binding");
exit(1);
}
// Start listening for the clients, here process will
// go in sleep mode and will wait for the incoming connection
listen(listen_fd, 5);
while (1) {
//Accepting client connection
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (client_conn < 0) {
perror("Client was not accepted...");
exit(1);
}
if ((pid = fork()) == 0) {
close(listen_fd);
bzero(buff, buff_size);
while ((bytes_read = read(client_conn, buff, buff_size)) > 0) {
fclose(file);
}
}
//Terminating child process and closing socket
close(client_conn);
exit(0);
bzero(buff, buff_size);
}
//parent process closing socket connection
close(client_conn);
}
return 0;
}
After the server forks a child it does close(client_conn). When accept assigns a socket descriptor to the new connection, it uses the lowest closed descriptor. Since you closed the socket earlier, it can be used for the next client that comes in.
This isn't a problem, because the connections are being managed by the child processes. They each have their own descriptor 5, and they don't interfere with each other.
You can get the client address & port returned to you by accept. Currently you are passing a null
client_conn = accept(listen_fd, (struct sockaddr *) NULL, NULL);
however just add a few lines like
struct sockaddr_in serv_addr, cli_addr;
int len = sizeof(cli_addr);
client_conn = accept(listen_fd, (struct sockaddr *) &cli_addr, &len);
and you have the client info in cli_addr.sin_addr.s_addr and cli_addr.sin_port.
You can get the pid of the child processing the connection from the return code of fork. That should give you all the information you need to create a table.
Related
I'm developing client-server software. On server's side I use this code:
int listener_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listener_socket < 0)
{
perror("opening socket error");
return;
}
/* set option for reuseaddr */
int mtrue = 1;
if(setsockopt(listener_socket,SOL_SOCKET,SO_REUSEADDR,&mtrue,sizeof(int)) != 0)
{
perror("setsockopt error");
return;
}
struct sockaddr_in serv_addr, cli_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
bzero((char *) &cli_addr, sizeof(cli_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* bind socket */
if (bind(listener_socket,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
{
perror("binding error");
return;
}
/* start listening */
listen(listener_socket,connections_limit);
int newsockfd;
/* infinite cycle */
while(1){
newsockfd = accept(listener_socket,(struct sockaddr*) &cli_addr,&clilen);
...
}
So my code blocks in accept() method and waiting for the new connection. When client connects, accept method returns correct non-negative socket descriptor (i can communicate with client using this descriptor) but it doesn't fill cli_addr structure. It remains zeroes. Why it happens?
i forgot this line before accept:
clilen = sizeof(cli_addr);
when i run both client and server i get this as result:
on server
Server is on
Client: XXX.X.X.X accepted
(that's the point that the program pauses until I type ctrl+C in client)
I try to get in while
I get in while
Client
AI Choise:Scissor
AI:Wins ratio 0,Looses ratio 0,Ties ratio 1
I get in while
Client
AI Choise:Scissor
AI:Wins ratio 0,Looses ratio 0,Ties ratio 2
on client
1)--> Paper
2)--> Scissor
3)--> Rock
4)--> Quit
^C
my code:
Server:
int main(int argc, char *argv[]){
printf("\nServer is on\n");
int sockfd, newsockfd, portno;
socklen_t clilen;
int Client_Choice;
struct sockaddr_in serv_addr, cli_addr;
int n,Who_Wins;
int ai_wins=0,ai_looses=0,ties=0,total=0,ai_win_ratio=0,ai_looses_ratio=0,ai_ties_ratio;
time_t t;
srand((unsigned) time(&t));
if (argc < 2) {
fprintf(stderr,"\nERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("\nERROR opening socket\n",sockfd);
}
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("\nERROR on binding\n",sockfd);
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
if (newsockfd < 0){
error("\nERROR on accept\n",sockfd);
}
char *cli_IP = malloc(sizeof(cli_addr.sin_addr.s_addr));
if (!cli_IP){
error("\nCould not allocate memory for conversion.\n",sockfd);
}
inet_ntop( AF_INET , &cli_addr.sin_addr.s_addr , cli_IP , INET_ADDRSTRLEN );
printf("\nClient: %s accepted\n",cli_IP);
printf("I try to get in while");
while(Client_Choice!=4){
printf("I get in while");
n= read( newsockfd, &Client_Choice, sizeof(Client_Choice) );
if(n < 0) {
error("\nERROR reading from socket\n",sockfd);
}
.
.
.
}
close(newsockfd);
close(sockfd);
return 0;
}
client
int main(int argc, char *argv[]){
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
int send;
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\n");
}
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\n");
}
while(send < 1 ||send > 4){
printf("\n\t1)--> Paper\n\t2)--> Scissor\n\t3)--> Rock\n\t4)--> Quit\n");
scanf("%d",&send);
n = write(sockfd,&send,sizeof(send));
if (n < 0){
error("ERROR writing to socket\n");
}
n = read(sockfd,&send,sizeof(send));
if (n == 0){
error("ERROR reading from socket\n");
}
}
close(sockfd);
return 0;
}
Your server is blocked waiting the message from the client. You have not reserved resources for dealing with several clients and only have a single process serving a single client (using the connection socket from accept(2)). That's the reason of it to appear blocking. In a normal server scenario, a new process is spawned by a fork(2) system call to deal with the socket obtained from accept(2) while the main process continues to accept(2) connections on the socket used for accepting new connections. As you are dealing with two sockets in server, but not attending the socket descriptor where accept(2) connections come in, it appears to be blocked, but it is actually ready to accept the commands from the active client. This is what is called a sequential server (it doesn't allow a connection before the first one terminates).
By the way, send is uninitialized before use in first while (send < 1 || send > 4) sentence so in case you get it casually equal to 2 (for example) you won't get client code into the while at all. This is only a point, probably there will be more. Why have you used different names for the message type interchanged between server and client? this makes more difficult to search for errors.
I have searched all about this question at this website.
my program scenario is:
there is one server that always listens for a request from a client.
there is one client that always requests a char from the server in 2 second periods
get the error message:
Too many open files" happened on socket() function after the program run about 1024 times.
My current solution is to increase the number of open files:
"ulimit -n 5000", but I don't think this is a perfect solution, because it will make the program run 5000 times.
So, does anybody have a better solution?
Environment:
ubuntu 10
c language
My code as following:
Client:
int sockfd;
struct sockaddr_in address;
int socket_port = 9734;
while (1) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
DieWithSystemMessage("socket() failed");//<<===========Too many open files
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = socket_port;
//Establish the connection to the server
if ((connect(sockfd, (struct sockaddr *) &address, sizeof(address)))
< 0)
DieWithSystemMessage("connect() failed");
if (rename_count % 2 == 0)
ch = 'A';
else if (rename_count % 2 == 1)
ch = 'B';
else
ch = 'E';
ssize_t numBytes = send(sockfd, &ch, strlen(&ch), 0);
if (numBytes < 0)
DieWithSystemMessage("send() failed");
else if (numBytes != strlen(&ch))
DieWithUserMessage("send()", "sent unexpected number of bytes");
//fflush(sockfd);
shutdown(sockfd, SHUT_RDWR);
rename_count++;
}
Server:
int server_sockfd, client_sockfd;
int server_len, client_len;
socklen_t clntAddrLen;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
uint64_t start_time_micro, end_time_micro;
int socket_num = 9734;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sockfd < 0)
DieWithSystemMessage("socket() failed");
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = socket_num;
if ((bind(server_sockfd, (struct sockaddr *) &server_address,
sizeof(server_address))) < 0)
DieWithSystemMessage("bind() failed");
if ((listen(server_sockfd, 5)) < 0)
DieWithSystemMessage("listen() failed");
while (1) {
char ch;
printf("\nserver waiting\n");
//accept a connect
clntAddrLen = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *) &client_address, &clntAddrLen);
if (client_sockfd < 0)
DieWithSystemMessage("accept() failed");
//reading and writing through client side
ssize_t numBytesRcvd = recv(client_sockfd, &ch, 1, 0);
if (numBytesRcvd < 0)
DieWithSystemMessage("recv() failed");
if (ch == 'A') {
rename_num = 0;//printf("A\n");
} else if (ch == 'B') {
rename_num = 1;//printf("B\n");
} else
;
printf("%d. Got it!!!\n", i);
close(client_sockfd);
}
close(server_sockfd);
You're shutting down the socket in the client but never closing it. It's not the same thing.
There is a big difference between shutdown() and close(). When you "shutdown" a socket, you're putting it into a "half-closed" condition where it is still possible to send or receive (depending on which half you shut down) over the connection.
The socket is still valid, TCP still maintains state information about the connection, and the port is still "open", and the socket/file-descriptor is still allocated to your process.
When you call close() the socket/file-descriptor is free'd but the rest remains. TCP must hold resources for some amount of time, typically 2 minutes (it depends on who did the close and some other things) during which the state information and the local port itself are still "in use".
So even though you may no longer exceed the file-descriptor limit for your process, it is theoretically possible to saturate the resources of the networking stack and still not be able to open a new connection.
For some reason my recvfrom() function for sockets is not blocking on my server code like it is supposed to. I am making a basic UDP server to create a rolling session key system.
What am I doing wrong here? It continues on after this line (before i put the (n < 1)) and was crashing. I am pretty sure recvfrom() is supposed to stop the execution of the program until it gets something from the client...
int sockfd, portNumber;
socklen_t clilen;
char buffer[BUFFER_LENGTH];
struct sockaddr_in serv_addr, from;
int n;
// Invalid arguments
if (argc < 2)
exit(0);
else if (atoi(argv[1]) > 65535 || atoi(argv[1]) < 1)
exit(0);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("Error opening socket.\n");
exit(0);
}
// Taken from reference
bzero((char *) &serv_addr, sizeof(serv_addr));
portNumber = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portNumber);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
printf("ERROR on binding.\n");
close(sockfd);
exit(0);
}
// Get initial session key request
int fromlen = sizeof(struct sockaddr_in);
n = recvfrom(sockfd, buffer, BUFFER_LENGTH, 0, (struct sockaddr *)&from, &fromlen);
if (n < 0)
{
printf("Error in receiving.\n");
exit(1);
}
Thanks
You're trying to use a stream socket for UDP;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
What you mean to do is probably;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
Trying to do recvfrom on an unconnected stream socket will most likely return immediately with an error. Next time, you may want to check errno for a hint.
I'm making a client program in C that has to deal with this situation:
1- server program receives udp datagram in port no 8080 sent by client with a port number X
2- server creates a new socket (TCP) in port number X
3- using this TCP socket, server reads a string sent by the client
(running on localhost)
I don't need to make the server program, it's already done. The points 1 and 2 are covered, but I've been a couple of days trying to work out the 3rd point and I'm not able to make it work ><
The code I've got for the client is this:
#define MYPORT 8080
int main(int argc, char *argv[ ]) {
int sockfd;
/* connector’s address information */
struct sockaddr_in their_addr;
struct hostent *he;
int numbytes;
int sockfd2, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc != 3) {
fprintf(stderr, "Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL) {
perror("Error obtaining the client. \n");
exit(1);
}
else printf("Client obtained\n");
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Error creating UDP socket\n");
exit(1);
}
else printf("UDP Socket done\n");
their_addr.sin_family = AF_INET;
printf("Port: 8080\n");
their_addr.sin_port = htons(MYPORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd2 < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
//sending port where the TCP socket will be associated
//server client connects correctly to this port
//and the code it's working fine in this point
if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("Client-sendto() error lol!");
exit(1);
}
//port is sent, now let's connect to the port by tcp and write the string
//not working properly from now on
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(atoi(argv[2]));
if (bind(sockfd2,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
//sending the string to the TCP Port...
if((numbytes = sendto(sockfd2, "hi", 2, 0, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))) == -1)
{
printf("Client-sendto()-TCP error\n");
exit(1);
}
if (close(sockfd) != 0) printf("Client-sockfd-UDP closing is failed!\n");
else printf("Client-sockfd-UDP successfully closed!\n");
if (close(sockfd) != 0) printf("Client-sockfd2-TCP closing is failed!\n");
else printf("Client-sockfd2-TCP successfully closed!\n");
return 0;
}
The code works for the first two steps, but in the last step, it seems it's not connecting well with the TCP port, because my client program ends but my server program says that he receives null.
And of course I'm always sending ports > 1024
Thanks in advance, any help will be so appreciated.
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
I haven't read all your code, but the above (at least) is wrong. You absolutely need to retain the return value of accept: it's the socket you need to write to!
accept returns a file descriptor for the new TCP socket that has just been created for communicating with the "server" in your case. You need to use that as the file descriptor you write your string to.
(The sendto call just after that, apart from using the wrong socket, is a bit suspicious since the server will have no way to determine how much data to read/where the message stops. Passing a length of 3 (to include the \0 byte, would be a bit less suspicious.)