How to know if the client has terminated in sockets - c

Suppose, I have a connected socket after writing this code..
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
How can I know at the server side that client has exited.
My whole program actually does the following..
Accepts a connection from client
Starts a new thread that reads messages from that particular client and then broadcast this message to all the connected clients.
If you want to see the whole code... In this whole code. I am also struggling with one more problem that whenever I kill a client with Ctrl+C, my server terminates abruptly.. It would be nice if anyone could suggest what the problem is..
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
/*CONSTANTS*/
#define DEFAULT_PORT 10000
#define LISTEN_QUEUE_LIMIT 6
#define TOTAL_CLIENTS 10
#define CHAR_BUFFER 256
/*GLOBAL VARIABLE*/
int current_client = 0;
int connected_clients[TOTAL_CLIENTS];
extern int errno;
void *client_handler(void * socket_d);
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;/* structure to hold server's address*/
int socket_d; /* listening socket descriptor */
int port; /* protocol port number */
int option_value; /* needed for setsockopt */
pthread_t tid[TOTAL_CLIENTS];
port = (argc > 1)?atoi(argv[1]):DEFAULT_PORT;
/* Socket Server address structure */
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; /* set family to Internet */
server_addr.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
server_addr.sin_port = htons((u_short)port); /* Set port */
/* Create socket */
if ( (socket_d = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Make listening socket's port reusable */
if (setsockopt(socket_d, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value,
sizeof(option_value)) < 0) {
fprintf(stderr, "setsockopt failure\n");
exit(1);
}
/* Bind a local address to the socket */
if (bind(socket_d, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
/* Specify size of request queue */
if (listen(socket_d, LISTEN_QUEUE_LIMIT) < 0) {
fprintf(stderr, "listen failed\n");
exit(1);
}
memset(connected_clients,0,sizeof(int)*TOTAL_CLIENTS);
for (;;)
{
struct sockaddr_in client_addr; /* structure to hold client's address*/
int alen = sizeof(client_addr); /* length of address */
int sd; /* connected socket descriptor */
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
else printf("\n I got a connection from (%s , %d)\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if (pthread_create(&tid[current_client],NULL,(void *)client_handler,(void *)sd) != 0)
{
perror("pthread_create error");
continue;
}
connected_clients[current_client]=sd;
current_client++; /*Incrementing Client number*/
}
return 0;
}
void *client_handler(void *connected_socket)
{
int sd;
sd = (int)connected_socket;
for ( ; ; )
{
ssize_t n;
char buffer[CHAR_BUFFER];
for ( ; ; )
{
if (n = read(sd, buffer, sizeof(char)*CHAR_BUFFER) == -1)
{
perror("Error reading from client");
pthread_exit(1);
}
int i=0;
for (i=0;i<current_client;i++)
{
if (write(connected_clients[i],buffer,sizeof(char)*CHAR_BUFFER) == -1)
perror("Error sending messages to a client while multicasting");
}
}
}
}
My client side is this (Maye be irrelevant while answering my question)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
void *listen_for_message(void * fd)
{
int sockfd = (int)fd;
int n;
char buffer[256];
bzero(buffer,256);
printf("YOUR MESSAGE: ");
fflush(stdout);
while (1)
{
n = read(sockfd,buffer,256);
if (n < 0)
error("ERROR reading from socket");
if (n == 0) pthread_exit(1);
printf("\nMESSAGE BROADCAST: %sYOUR MESSAGE: ",buffer);
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
pthread_t read_message;
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,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
if (pthread_create(&read_message,NULL,(void *)listen_for_message,(void *)sockfd) !=0 )
{
perror("error creating thread");
}
while (1)
{
fgets(buffer,255,stdin);
n = write(sockfd,buffer,256);
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
}
return 0;
}

After accepting the connection, your recv() on the socket will return 0 or -1 in special cases.
Excerpt from recv(3) man page:
Upon successful completion, recv()
shall return the length of the message
in bytes. If no messages are available
to be received and the peer has
performed an orderly shutdown, recv()
shall return 0. Otherwise, -1 shall be
returned and errno set to indicate the
error.
So, if your client exited gracefully, you will get 0 from recv() at some point. If the connection was somehow lost, you may also get -1 and checking for appropriate errno would tell you if the connection was lost of some other error occured. See more details at recv(3) man page.
Edit:
I see that you are using read(). Still, the same rules as with recv() apply.
Your server can also fail when trying to write() to your clients. If your client disconnects write() will return -1 and the errno would probably be set to EPIPE. Also, SIGPIPE signal will be send to you process and kill him if you do not block/ignore this signal. And you don't as I see and this is why your server terminates when client presses Ctrl-C. Ctrl-C terminates client, therefore closes client socket and makes your server's write() fail.
See mark4o's answer for nice detailed explanation of what else might go wrong.

If the client program exits, then the OS on the client will close its end of the socket. When you call recv() it will return 0, or -1 with errno ECONNRESET if a TCP RST has been received (e.g. because you attempted to send data after the client had closed). If the whole client machine goes down, or the network becomes disconnected, then in that case you may not receive anything if the server is not trying to send anything; if that is important to detect, you can either send some data periodically, or set the SO_KEEPALIVE socket option using setsockopt() to force it to send a packet with no data after long periods (hours) of inactivity. When no acknowledgment is received, recv() will then return -1 with errno ETIMEDOUT or another error if more specific information is available.
In addition, if you attempt to send data on a socket that has been disconnected, by default the SIGPIPE signal will terminate your program. This can be avoided by setting the SIGPIPE signal action to SIG_IGN (ignore), or by using send() with the MSG_NOSIGNAL flag on systems that support it (Linux).

Related

Is it possible to launch multiple servers listening to a different IP socket address?

I'm trying to launch multiple servers, at once, in a c program. For the sake of simplicity let's say 5 servers.
If I understand well the sockets, each of them must be listening to a different IP socket address (different PORT, different IP interface address).
I thought to do that inside a loop, incrementing port number by i at each turn. Here's my current code just to launch one server. I know it's possible with bash by launching the same process in background, but in C I really don't know how to do that and if it's even possible
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
long PORT;
int main(int argc, char const *argv[])
{
/* 1. Open a socket
2. Bind to a address(and port).
3. Listen for incoming connections.
4. Accept connections
5. Read/Send
*/
int listenerSocket; /* socket for accepting connections */
int clientSocket; /* socket connected to client */
struct sockaddr_in server;
struct sockaddr_in client; /* client address information */
char buf[100]; /* buffer for sending & receiving data */
int errnum;
listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if(listenerSocket == -1){
perror("erreur lors de la création du socket");
}
PORT = strtol(argv[1], NULL, 10);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port= htons(PORT);
if (bind(listenerSocket, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
puts("Server waiting for connection...");
while(1){
if (listen(listenerSocket, 5) < 0){
perror("listen failed");
exit(EXIT_FAILURE);
}
int c = sizeof(client);
if((clientSocket = accept(listenerSocket, (struct sockaddr*) &client, &c)) < 0){
puts("error accepting the request");
perror("Accept()");
}
puts("connection accepted");
while(1){
if( recv(clientSocket, buf, sizeof(buf), 0) < 0) {
errnum = errno;
perror("Recv()");
printf("val printed by errno: %d\n",errno);
}
printf("Message : %s\n", buf);
}
if (send(clientSocket, buf, sizeof(buf), 0) < 0)
{
perror("Send()");
exit(7);
}
close(clientSocket);
close(listenerSocket);
printf("Server ended successfully\n");
exit(0);
}

Simple echo program using sockets in C echoing incorrect message after the first run

I am trying to learn the basic of network communication using sockets in C. My client program takes in a message from the user, echoes it server side and back, and prints out the received message. When I fire both of them up for the first time, they both work exactly as expected. However, if I quit the client side and then fire it up again while keeping the server program running, my echoed messages become off by one.
I assumed it was because the last message is getting caught in the pipe or something, and after poking around, I saw that someone suggested to use shutdown() to flush out the pipe, but that doesn't seem to be working. I also tried to zero out the buffers wherever I thought they may be lingering, but that didn't seem to help, either.
server.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
listening();
//Once first socket has been connected, begin echoing process
int i = 0;
while (1)
{
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
i++;
}
close(serverSocket);
return 0;
}
client.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#define PORT 12403
#define LOCALHOST "127.0.0.1"
#define BUFFER_MAX 1024
int socketStatus = 0;
void sigpipeHandler()
{
perror("Connection to server terminated\n");
socketStatus = 0;
}
int main()
{
int mySocket;
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
int count = 0;
//Create socket
if ((mySocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Get IP address of required host machine
char* hostName = "<host name removed>";
int portNumber = PORT;
char* ipAddr = NULL;
struct hostent* host = NULL;
host = gethostbyname(hostName);
ipAddr = inet_ntoa(*((struct in_addr*) host->h_addr_list[0]));
//Initialize server information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(portNumber);
if (inet_aton(ipAddr, (struct in_addr *)&socketInfo.sin_addr.s_addr) == 0)
{
perror("Error assigning IP address");
exit(errno);
}
//Set up sigpipe handler
signal(SIGPIPE, sigpipeHandler);
//Connect to server
if (connect(mySocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error connecting");
exit(errno);
}
//Indicate that socket is OK
socketStatus = 1;
while(1)
{
if(!socketStatus) {shutdown(mySocket, SHUT_WR); break;}
printf("Please enter a command.\n");
char command[BUFFER_MAX];
bzero(command, BUFFER_MAX);
fgets(command, sizeof(command), stdin);
send(mySocket, command, BUFFER_MAX, 0);
//Get echoed message
bzero(buffer, BUFFER_MAX);
recv(mySocket, buffer, sizeof(buffer), 0);
printf("Echo [%d]:%s\n", ++count, buffer);
}
//Close socket
close(mySocket);
return 0;
}
I did some cleanup on your server code and this seems to work.
For my testing, the client code is unchanged. But, as others have suggested, you should check the error codes from send and recv. Also, note that if you ctrl-c the server, the client will hang in the fgets, so it won't detect the server abort until you hit return after the prompt. Not a big deal, but I thought I'd mention it.
I also added a fork so you can have multiple clients talking to the same server instance simultaneously.
I tested this with two clients [in two xterm windows] talking with the single server instance.
I moved your echo code into a new function docomm. A small difference from your code is that any error from either recv or send breaks out of the loop and closes the connection. All connections from new clients are guaranteed to start with a recv call.
In your code, you would not always break out of the loop, but close the connection and call listening again. This would happen for either send or recv. If it happened on the wrong one, this might be the source of the problem you were having because you could do a send before a recv to a new client initially.
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
int forkflg = 1;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
void
docomm(void)
{
char buffer[BUFFER_MAX];
//Once first socket has been connected, begin echoing process
int i = 0;
while (1) {
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
break;
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
break;
i++;
}
printf("close\n");
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
while (1) {
listening();
if (! forkflg) {
docomm();
continue;
}
pid_t pid = fork();
if (pid == 0) {
docomm();
exit(0);
}
while (waitpid(0,NULL,WNOHANG) > 0);
}
close(serverSocket);
return 0;
}
UPDATE:
Just from a glance: 1) Can I ask why you created a fork flag if you never change the value of it? Should it be changed somewhere?
I used forkflg so you can set it to zero (e.g. int forkflg = 0;) to run sequentially. Or, you could add some code and parse argv looking for an option (e.g. -f) to set/clear it [for testing/debug purposes]. For production code, you'd want forkflg to be set and could remove the flag and just do the fork case always [adjusting the code to match].
Just tracing through the program mentally, it seems like the forking section will never be executed. Correct me where I'm wrong: after initially setting the socket to listen, the while loop will enter, and listening() will be called. Execution will halt in listening() until a connection is accepted.
Yes, that's true.
Control will return to main, where docomm() gets called. Control stays in docomm() until the connection breaks, at which point it returns to main and continue gets called, skipping the fork stuff and starting the process over again. So does the fork stuff ever get executed?
What you're describing is the behavior if forkflg is zero.
The fork is called if forkflg is set. Note that, in that case, docomm is called in the child and not the parent (because fork returned 0). So, the parent will not be blocked while the child does the echoing.
Thus, the parent returns immediately and is free to do the waitpid loop to reap any old children and restart the main/outer loop.
The waitpid loop only happens when a new connection comes in, so several children may have already terminated and will stay in zombie state until the waitpid loop gets executed [which will reap any/multiple pending children].
A cleaner way to reap the children might be to set up a signal handler for SIGCHLD and have it do the waitpid loop. This would reap all spent children immediately, without having to wait for a new connection to roll in.
Or, with the signal handler, add the waitpid loop to listening [inside the current loop] because if a SIGCHLD signal comes in, accept will return immediately with errno set to EINTR

recvmsg() blocking on the first call but not on subsequent calls

I am having a problem with my client-server C program.
There are 2 main parts to the program. In part one, a message is sent from a Kernel module to a Userspace listener via multicast. I have tried and tested this part of the program many times and it works as expected.
The second part of the program transfers the message received to another machine (Machine 2). So, the Userspace listener from Machine 1 gets the message from the Kernel and then acts as a Client, opening up a socket between Machine 1 and Machine 2. The Server in Machine 2 receives the message and prints it to stdout. It then waits for another message.
The issue seems to be that the recvmsg() function blocks the first time but not in subsequent iterations. It is as if the information in the socket stays there and therefore prevents recvmsg() from blocking. The result is that the same piece of information is transferred in a loop.
I could be wrong on this recvmsg() problem. Perhaps someone has more experience and can point me in the right direction. The code and output are below. Many thanks.
NetLinkUser_Client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#define MAX_PAYLOAD 1024
#define MY_GROUP 1
#define OUT_PORT "5001"
#define OUT_IP "192.168.xxx.xxx"
void client(char *msg) {
int socketfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
portno = atoi(OUT_PORT);
/* Create a socket point */
socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0) {
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(OUT_IP);
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);
/* Now connect to the server */
if (connect(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
exit(1);
}
/* Now send a message to the server, this message
* will be read by server
*/
char buffer[MAX_PAYLOAD];
bzero(buffer,MAX_PAYLOAD);
strcpy(buffer, msg);
printf("\nThe contents of the buffer is: %s\n", buffer);
printf("\nThe length of the buffer is: %d\n", strlen(buffer));
/* Send message to the server */
n = write(socketfd, buffer, strlen(buffer));
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
bzero(buffer,MAX_PAYLOAD);
printf("%s\n",buffer);
close(socketfd);
}
int main(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if(sock_fd<0)
{
printf("Error creating socket because: %s\n", strerror(errno));
return -1;
}
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
ssize_t recvmsg_err = 0;
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));
memset(nl_msghdr, 0, NLMSG_SPACE(1024));
// The issue is not related to zeroing out msghdr
printf("The struct member msghdr.msg_namelen has the value : %d before zeroing out\n", msghdr.msg_namelen);
memset(&msghdr, 0, sizeof(msghdr));
printf("The struct member msghdr.msg_namelen has the value : %d after zeroing out\n", msghdr.msg_namelen);
memset(&iov, 0, sizeof(iov));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(1024);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
printf("The struct member msghdr.msg_namelen has the value : %d after initialization\n", msghdr.msg_namelen);
printf("Waiting to receive message\n");
// Execution not pausing here WHY??
printf("recvmsg() should wait here\n");
recvmsg_err = recvmsg(sock_fd, &msghdr, 0);
if(recvmsg_err == -1)
{
perror("Error in recvmsg\n");
}
printf("The value returned by recvmsg() is %d\n", recvmsg_err);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
printf("Kernel message: %s\n", kernel_msg); // print to android logs
client(kernel_msg);
}
close(sock_fd);
}
MsgServer.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#define MAX_PAYLOAD 1024
void doprocessing (int sock) {
int n;
char buffer[MAX_PAYLOAD];
bzero(buffer,MAX_PAYLOAD);
n = read(sock,buffer,MAX_PAYLOAD);
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("The length of the buffer is %d\n", strlen(buffer));
printf("Here is the message: %s\n",buffer);
}
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[1024];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, 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);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
printf("Waiting for initial connection in doProcessing() while loop\n");
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0) {
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
exit(0);
}
else {
close(newsockfd);
}
} /* end of while */
}
Client sample output
The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The length of the buffer is: 54
The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The length of the buffer is: 54
Server Sample Output
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
I understand that this might be hard to reproduce considering Netlink is involved. Thanks in advance for your help and sorry for the long post.
Edit: I have changed the code to check for errors in recvmsg() as was suggested but the output is exactly the same.

Data sending error in socket

I have made simple server and client in c.Client waits for server until server is started.When i start the server data transmission between server and client is happening as per my expectation.When i close the server(not client) and again restarts the server,the first string from client to server is not transmitting.and then afterwards the client can send strings to server.So after restarting server client can't transmit first string to server.
Here is my client code(client.c),
/*header*/
#include<signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
/*macros*/
/*size of the buffer*/
#define DATA_SIZE 200
/*function for thread*/
void *recieve_handler(void *);
/*stores the id of main thread*/
pthread_t main_id;
/*socket variable*/
int sockfd=0;
/*specifies the port number*/
#define PORT 5000
/*lenth of ip*/
#define LENGTH_OF_IP 100
int quit = 1;
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
int main(int argc, char *argv[])
{
/*buffer to send and receive*/
char received_data[DATA_SIZE],send_data[DATA_SIZE],server_ip[LENGTH_OF_IP],buf[DATA_SIZE]
,user_name[DATA_SIZE];
/*declare pointer for client config file*/
FILE* config_file;
/*flags*/
int clear = 1,server_port,usb_trap_on,n;
/*declaring socket object*/
struct sockaddr_in serv_addr;
/*thread declaration*/
pthread_t thread_id;
/*welcome messsage*/
printf("This is clientn");
printf("Enter somethingn");
printf("Server echos back the datan");
/*open client configuration file*/
if ((config_file = fopen("client.config","rw+")) == NULL)
{
printf("Could not open client config filen");
return 1;
}
/*parsing the file*/
while (fgets(buf, sizeof buf, config_file) != NULL) {
if (sscanf(buf,"IP=%s PORT=%d",server_ip,&server_port) == 2)
printf("%s %dn",server_ip,server_port);
if (fscanf(config_file,"usb_trap=%d",&usb_trap_on) == 1)
printf("usb flag is %dn",usb_trap_on);
}
/*create the socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("n Error : Could not create socket n");
return 1;
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*inialize all the variable of object serv_addr with 0*/
memset(&serv_addr, '0', sizeof(serv_addr));
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(server_port);
/* inet_pton - convert IPv4 and IPv6 addresses from text to binary form
* it returns 0 when coversion is unsucessful*/
if(inet_pton(AF_INET, server_ip, &serv_addr.sin_addr)<=0){
printf("n inet_pton error occuredn");
return 1;
}
/*connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
*if connection is established then the memory for server will be
*allocated in client's memory
*and strting address of that memory is stored in scokfd
*i will return negative value if operation fails. */
while(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
printf("Wating for server to connectn");
sleep(1);
}
printf("Connection is donen");
printf("enter somethingn");
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*create the thread to receive data*/
if( pthread_create( &thread_id , NULL , recieve_handler , (void*)&sockfd) < 0) {
perror("could not create thread");
return 1;
}
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
/*read from server*/
n = read(sockfd,received_data,sizeof(received_data));
/*if read error is occurred*/
if (n < 0) {
printf("Can't read received_datan");
break;
pthread_exit(&n);
}
if(n == 0) {
printf("Can't read received_datan");
break;
}
puts(received_data);
}
pthread_cancel(&thread_id);
/*close socket*/
if(!close(sockfd))
printf("Socket is closedn");
printf("Server is sutdown!!!!!!!!!!!!!n");
system("./client");
return 0;
}
void *recieve_handler(void *socket_desc)
{
/*received data buffer*/
char send_data[DATA_SIZE];
/*status flag*/
int n;
/*if pointer is empty*/
if(socket_desc == NULL) {
printf("socket_desc is NULLn");
n = 0;
pthread_exit(&n);
}
/*socket number*/
int sock = *(int*)socket_desc;
/*infinite loop*/
while (1){
/*clear buffer*/
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
if((write(sock, send_data, strlen(send_data)+1)) == -1)
{
/*write data to server*/
printf("could not writen");
break;
}
}
}
here is my server code(server.c),
/*header*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
/*macros*/
/*maximum client that can be connected to server*/
#define MAX_CLIENT 10
/*size of the buffer*/
#define DATA_SIZE 200
/*specifies the port number*/
#define PORT 7000
int listenfd;
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
int main(int argc, char *argv[])
{
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*to store the recived data*/
char recived_data[DATA_SIZE];
/*sockaddr_in is a structure defined in netinet/in.h file.we are creating object of that
*strucure. */
struct sockaddr_in serv_addr;
/*flags*/
int connfd = 0 , clear = 1 ;
/*welcome message*/
printf("This simple server\n");
printf("It will echo data to client\n");
printf("If quit is recived from client then server will be existed\n");
/*Created socket*/
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("Can't create socket\n");
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*tells that any client can connect*/
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(PORT);
/*specifies port and adress of the socket*/
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
/*it will listen for connection
*MAX_CLIENT specifies the maximum client server can handle*/
listen(listenfd, MAX_CLIENT);
/*accept will assign the memory to client in server's memory area.here
*connfd has starting adress of assigned memory to client in server
*memory.*/
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
/*inet_ntoa(serv_addr.sin_addr) will return the adress of client*/
printf("[Server] Server has got connected from %s.\n", inet_ntoa(serv_addr.sin_addr));
printf("server waiting\n");
while(1){
/*read the data from memory and put in buffer*/
if(read(connfd, recived_data, sizeof(recived_data))){
/*if quit is recived then break the loop*/
if(!strcmp(recived_data,"quit"))
break;
/*put data on screen*/
puts(recived_data);
/*echo the data back to client*/
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
break;
}
else
{
printf("Could not read\n");
}
}
read(connfd, recived_data, sizeof(recived_data));
printf("server exiting\n");
/*close socket*/
close(connfd);
return(0);
}
here is client.config file(which is used be client to get ip,port of server)
IP=192.168.3.17 PORT=7000
usb_trap=0
This is my output of client when server is first time connected,
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
hello
i am jay
i am jay
Above output is as per my expectation.
Now below is my output of client when server is reconnected(server is disconnected ,and then started again)
Socket is closed
Server is sutdown!!!!!!!!!!!!!
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
could not write
jay
jay
So in above output client can't write first string to server.
Client signal handler:
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
Everything wrong here that could be wrong. No error checking. You can't do I/O in signal handlers. You can't block in signal handlers. You don't need to 'write null to server'. Exiting the application will close the socket, or reset it.
Client:
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
Unnecessary. Remove.
if (n < 0) {
printf("Can't read received_datan");
A pointless message. You got an error. Print the error, with perror(), or by incorporating strerror() into the message.
if(n == 0) {
printf("Can't read received_datan");
An incorrect message. This situation is not the same as the previous one. You got end of stream. The peer has disconnected. Say so.
puts(received_data);
Wrong. The data received is only valid up to n bytes. The correct way to print it is via printf("%.*s", n, received_data);
Client 'receive handler':
void *recieve_handler(void *socket_desc)
Apart from the mis-spelling, why is this called a receive handler when it doesn't receive? and does send?
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
You probably meant '\0' here, as there are numerous other backslashes missing from your code, but the memset() is completely unnecessary. Remove.
Server signal handler:
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
This is all nonsense from start to finish. You can't do I/O in a signal handler; you can't do I/O with a listening socket; you can't block in a signal handler; and you don't need to do any of it. The operating system will either close or reset the socket. Either way the peer will find out via the return value of read() or recv().
Server loop:
if(read(connfd, recived_data, sizeof(recived_data))){
Incorrect. It is never correct to call read() or recv() without storing the return value into a variable. You have to test it for -1, test it for zero, and otherwise use it as the length of data received. You can't accomplish that without a variable. See your own client code for an example, after my corrections.
if(!strcmp(recived_data,"quit"))
Invalid. There is no guarantee that you will receive a null-terminated string. And you haven't checked for EOS or an error first.
puts(recived_data);
Invalid for the same reason as the puts() in the client as discussed above.
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
Invalid. The length of the data received is given by the return value of read() if positive, not by strlen(). See discussion above.
else
{
printf("Could not read\n");
}
See discussion above about indiscriminate error messages like this. No use at all.
read(connfd, recived_data, sizeof(recived_data));
What is this? Remove.
Problem is that you are not canceling the thread properly.
Use
pthread_cancel(thread_id);
instead of
pthread_cancel(&thread_id);
So now thread will be canceled.and that thread will not be lived.

Unable to connect with multiple client with my socket server program

My socket server program is mentioned below. It works fine with the single client but when I try to connect it with another client at the same time, I am unable to connect. But I have defined MAX_CLIENTS in my program as 2 but still why I am unable to connect with multiple clients? What is the correct process to connect with multiple client? Will I be able to connect with multiple client by modifying this code? Any possible fix?
Socket Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
main (int argc, char **argv){
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof (struct sockaddr_in);
int data_len;
char data [MAX_DATA];
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("socket: ");
exit (-1);
}
printf("after socket");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = INADDR_ANY;
bzero (&server.sin_zero, 8);
printf("after server");
if ((bind (sock, (struct sockaddr*)&server, sockaddr_len)) == -1)
{
perror ("bind");
exit (-1);
}
printf("after bind");
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror ("listen");
exit (-1);
}
printf("after listen");
while(1)
{
if ((new = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror ("accept");
exit (-1);
}
printf("after new");
printf("New client connected from port no %d and IP %s\n",ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while (data_len)
{
data_len = recv (new, data, MAX_DATA, 0);
if (data_len)
{
send (new, data, data_len, 0) ;
data [data_len]='\0';
printf("Sent mesg: %s", data);
}
printf("after datalen");
}
printf("Client Disconnected\n");
close(new);
}
printf("after close new");
close (sock);
}
Your program is single-threaded, and only does one thing at a time. When you have accepted a socket connection from a client (in your outer while loop) you start communicating with that client (in your inner while loop), and you don't get back to the accept call until the first client has disconnected.
Either use threads, with one thread that waits for new connections and one additional thread for each client, waiting for input from that client, or use the select call, which lets you wait for input simultaneously from several different sources.

Resources