local linux socket receives old data - c

I just wrote a program that uses local socket to communicate between two processes
if client send one message to server, and then close the connection, server would only receive one message
clent:
send(srvfd,data,size,0)
close(srvfd)
server:
n=recv(fd,buf,size,0)
however, if client send one message, and server also send one message (any string) back to client, then client close the connection, server would receive the older message that client sends
client:
send(srvfd,data,size,0)
n=recv(srvfd,buf,size,0)
close(srvfd)
server:
n=recv(fd,buf,size,0)
send(fd,"response",8,0)
n=recv(fd,buf,size,0) //receive the first message again
here is my initialize code:
struct sockaddr_un srvAddr;
int listenFd = socket(PF_UNIX, SOCK_STREAM, 0);
if (listenFd < 0) {
perror("cannot create communication socket");
throw runtime_error("cannot create communication socket");
}
srvAddr.sun_family = AF_UNIX;
strncpy(srvAddr.sun_path, sockFile.c_str(), sockFile.size());
unlink(sockFile.c_str());
int ret = bind(listenFd, (struct sockaddr*) &srvAddr, sizeof(srvAddr));
if (ret == -1) {
perror("cannot bind server socket");
close(listenFd);
unlink(sockFile.c_str());
throw runtime_error("cannot bind server socket");
}
ret = listen(listenFd, BACKLOG);
if (ret < 0) {
perror("cannot listen the client connect request");
close(listenFd);
unlink(sockFile.c_str());
throw runtime_error("cannot listen the client connect request");
}

send(fd,"response",8,0)
n=recv(fd,buf,size,0) //receive the first message again
No you didn't. What you got got was n == 0, meaning end of stream. It also means that zero bytes were transferred into the buffer, so none of what's now in the buffer is now meaningful.
Don't ignore return codes.

Related

How to handle TCP client disconnect in C

I am trying to write a basic TCP server that streams serial data to a client. The server would connect to a serial device, read data from said device, and then transmit it as a byte stream to the client. Writing the TCP server is no problem. The issue is that the server will crash when a client disconnects. In other languages, like Python, I can simply wrap the write() statement in a try-catch block. The program will try to write to the socket, but if the client has disconnected then an exception will be thrown. In another project, this code snippet worked for me:
try:
client_socket.send(bytes(buf, encoding='utf8'))
except Exception as e:
logger.info("Client disconnected: %s", client_id)
I can handle client disconnects in my C code, but only by first reading from the socket and checking if the read is equal to 0. If it is, then my client has disconnected and I can carry on as usual. The problem with this solution is that my client has to ping back to the server after every write, which is less than ideal.
Does anyone know how to gracefully handle TCP client disconnects in C? My example code is shown below. Thank you!
// Define a TCP socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Allow for the backlog of 100 connections to the socket
int backlog = 100;
// Supply a port to bind the TCP server to
short port = 9527;
// Set up server attributes
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
// Set the socket so that we can bind to the same port when we exit the program
int flag = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
perror("setsockopt fail");
}
// Bind the socket to the specified port
int res = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (res < 0) {
perror("bind fail");
exit(1);
}
// Listen for incoming connections
if (listen(sockfd, backlog) == -1) {
perror("listen fail");
exit(1);
} else {
printf("Server listening on port\n", port);
}
for(;;) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s, port %d\n", buff, cli_port);
for(;;) {
// Read from serial device into variable here, then send
if(send(connfd, "Data...Data...Data\n", 19, 0) < 0) {
printf("Client disconnected...\n");
break;
}
}
}
Looks like a duplicate of this, this and this.
Long story short you can't detect the disconnection until you perform some write (or read) on that connection. More exactly, even if it seems there is no error returned by send, this is not a guarantee that this operation was really sent and received by the client. The reason is that the socket operations are buffered and the payload of send is just queued so that the kernel will dispatch it later on.
Depending on the context, the requirements and the assumptions you can do something more.
For example, if you are under the hypothesys that you will send periodic message at constant frequency, you can use select and a timeout approach to detect an anomaly.
In other words if you have not received anything in the last 3 minutes you assume that there is an issue.
As you can easily found, this and this are a good read on the topic.
Look at that for a far more detailed explanation and other ideas.
What you call the ping (intended as a message that is sent for every received packet) is more similar to what is usually known as an ACK.
You only need something like that (ACK/NACK) if you also want to be sure that the client received and processed that message.
Thanks to #emmanuaf, this is the solution that fits my project criteria. The thing that I was missing was the MSG_NOSIGNAL flag, referenced here.
I use Mashpoe's C Vector Library to create a new vector, which will hold all of my incoming client connections.
int* client_array = vector_create();
I then spawn a pthread that continually reads from a serial device, stores that data in a variable, and then sends it to each client in the client list
void* serve_clients(int *vargp) {
for(;;) {
// Perform a microsleep
sleep(0.1);
// Read from the Serial device
// Get the size of the client array vector
int client_vector_size = vector_size(vargp);
for(int i = 0 ; i < client_vector_size ; i++) {
// Make a reference to the socket
int* conn_fd = &vargp[i];
/*
In order to properly handle client disconnects, we supply a MSG_NOSIGNAL
flag to the send() call. That way, if the client disconnects, we will
be able to detect this, and properly remove them from the client list.
Referenced from: https://beej.us/guide/bgnet/html//index.html#sendman
*/
if (send(*conn_fd, "Reply from server\n", 18, MSG_NOSIGNAL) < 0) {
printf("Client disconnected...\n");
// Close the client connection
close(*conn_fd);
// Remove client socket from the vector
vector_remove(vargp, i);
// Decrement index and client_server_size by 1
i--;
client_vector_size--;
}
}
}
}
To spawn the pthread:
// Spawn the thread that serves clients
pthread_t serving_thread;
pthread_create(&serving_thread, NULL, serve_clients, client_array);
When a new connection comes in, I simply add the new connection to the client vector
while(1) {
// Wait for incoming connection
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len);
if (-1 == connfd) {
perror("Could not accept incoming client");
continue;
}
//Resolving Client Address
char buff[INET_ADDRSTRLEN + 1] = {0};
inet_ntop(AF_INET, &cliaddr.sin_addr, buff, INET_ADDRSTRLEN);
uint16_t cli_port = ntohs(cliaddr.sin_port);
printf("connection from %s:%d -- Connfd: %d\n", buff, cli_port, connfd);
// Add client to vector list
vector_add(&client_array, connfd);
}
In the end, we have a TCP server that can multiplex data to many clients, and handle when those clients disconnect.

Socket freezes when write is attempted

I am writing a FTP server in C. Currently I am struggling with passive connection. I maintain a connection via sockets, and I have two of those. The first one is const int a_socket, it is created when a client connects and it accepts all client commands and sends response codes from the server. The second one is int p_socket, which is only connected when passive mode is requested by the client It is supposed to send large data. I get an error when I try to send anything through p_socket - the server gets stuck in the write function and the client (I am currently testing against Filezilla) recieves ECONNRESET. It also appears that the server is sending RST instead of the message.
I create the sockets with create_socket
int create_socket(int *ap_socket, const int a_port) {
// variables
struct sockaddr_in serverAddr;
int yes = 1;
// create address
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(a_port);
// create socket
if ((*ap_socket = socket(serverAddr.sin_family, SOCK_STREAM, 0)) < 0) {
perror("service_create(): create socket");
return 0;
}
// set options
if (setsockopt(*ap_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
perror("service_create(): socket opts");
return 0;
}
// bind socket
if (bind(*ap_socket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
perror("service_create(): bind socket");
close(*ap_socket);
return 0;
}
// listen to socket
if (listen(*ap_socket, SERVER_SOCKET_BACKLOG) < 0) {
perror("service_create(): listen socket");
close(*ap_socket);
return 0;
}
return 1;
}
The client connects without issues on both sockets, but only a_socket is able to send any data. I am using the following function to check the sockets.
int check_socket(const int sd) {
int result = write(sd, "\0", 2);
if (result >= 0) {
return 1;
}
else {
return 0;
}
}
I am using wireshark to view the packets and I do all of the testing on localhost. Socket a_socket connects client
port 43684 to FTP port 21 on server (not seen in the log). Server provides port 20 for passive connection and client connects via port 50601.
Last three lines of the log show results of check_socket. Test message sent from a_socket (\000\000) arrives fine and is ACKned by the client, but the same message sent from p_socket results in RST right on the next line.
I am not fluent in C and I am a beginner in sockets and networking, so any help will be appreciated.

Getting connection reset by peer during TCP socket connection?

i'm making a small client-server application,where server forks a child process after accept,for multiple connections while the client connects to it ,sends a message and receives a response. following is my code fragment:
-- client.c
char buffer[256];
portno=5001;
/* Create a socket point */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
/* Now connect to the server */
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
exit(1);
}
/* Now ask for a message from the user, this message
* will be read by server
*/
while(1)
{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
/* Send message to the server */
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
/* Now read server response */
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if(n==0)
{
perror("nothing to read");
}
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("%s\n",buffer);
}
--server.c
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
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) {
newsockfd = accept(sockfd, (struct sockaddr *)NULL,NULL);
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)
{
while(1)
{
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
/** exit(0); **/
}
}
else {
close(newsockfd);
}
} /* end of while */
}
void doprocessing (int sock) {
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if(n==0)
{
perror("nothing to read");
}
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("Here is the message: %s\n",buffer);
n = write(sock,"I got your message",18);
if (n <= 0) {
perror("ERROR writing to socket");
exit(1);
}
}
when i run the both,O/P is following:
Please enter the message: arjun
I got your message
Please enter the message: gaur
ERROR reading from socket: Connection reset by peer
Please help.how to resolve this
The forked child process is exiting without closing newsockfd. On some platforms that causes a connection reset instead of an orderly close.
You also need to check the result of recv() for zero and handle it correctly, i.e. not as an error, and you also need to use a positive return value correctly, e.g. instead of
printf("%s\n",buffer);
it should be
printf("%.*s\n",n,buffer);
What happens is:
Server starts listening.
Client connects to listening server.
Server forks of process serving client.
Client sends data.
Serving process as of 3. receives date from client and prints it.
Serving process as of 3. sends response to client.
Serving process as of 3. exists/ends and with this its accepted socket (the peer to the client) gets closed.
Client receives response and prints it.
Client tries to send more data to the serving process as of 3..
Client tries to read more data from the serving process as of 3..
Step 10. fails because the serving process as of 3. already ended (step 7.)
Your client does this:
Connect to the server
Send some data to the server
Receive some data from the server
Send some data to the server
Receive some data from the server
...
but your server does this (possibly with multiple connections at once):
Wait for a connection
Receive some stuff from the client
Send some stuff to the client
Close the connection (by exiting the only process that has the connection open)
So the server closes the connection when the client is about to send some more data, and the client gets an error because the server closed the connection.
You need to either make the server keep receiving and sending data in a loop (so it can happen several times on the same connection), or make the client make a new connection each time it wants to send something.

segmentation fault with accept() on linux

I have a problem with a client/server programm on linux.
I wrote a server programm wich is sending data cyclic to one conneted client.
Now I want to detect, if the client close the connection to the server. When the connection is closed from the client, i want to wait with accept(...) for an new connection.
Here the critical parts of my code:
error = send(client_sock, Zeichen, 1, MSG_NOSIGNAL);
if(error < 0)
{
connected = 0;
printf("Error, write on TCP Socket failed!!! Reconnecting... \r\n");
close(serverSocket);
initServer();
}
int initServer(void)
{
int *new_sock;
socklen_t size;
struct sockaddr_in server, client;
serverSocket = socket(AF_INET , SOCK_STREAM , 0); //Create socket
if (serverSocket == -1)
{
printf("Could not create socket \r\n");
return 0;
}else
{
printf("Socket created \r\n");
}
server.sin_addr.s_addr = inet_addr(IPAdresse);
server.sin_family = AF_INET;
server.sin_port = htons(TCPPort);
if(bind(serverSocket,(struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("bind failed. Error \r\n");
return 0;
}else
{
printf("bind done \r\n");
}
listen(serverSocket, 1);
printf("Waiting for incoming connections... \r\n");
size = sizeof(sockaddr_in);
printf("size of sockaddr_in: %i \r\n", size);
client_sock = accept(serverSocket, (struct sockaddr *)&client, &size);
if (client_sock < 0)
{
printf("accept failed \r\n");
return 0;
}else
{
connected = 1;
return 1;
}
}
The first time it works fine, I can connect and can send data over the socket. When the client close the connection the error is detected, I close the socket an start the server again to wait for a new connection. But than I get a segmentation fault when I do the accept(..) for the second time!!!
Can someone help me please!!! Thanks a lot!
It's not clear what you're doing when the client connection closes. I see no loop in your code, and yet you're suggesting that accept() is called more than once.
Without seeing the rest or the code, I can only speculate that:
you're repeatedly calling initServer(), hence attempting to recreate the same server socket over and over (which, of course, would be bad),
or
you're calling accept() again somewhere else in your code, most likely with corrupt arguments.
At the very least, what your server-side code should do is initialize the server socket once, then loop around accept(), like so:
call socket() once
call bind() once
call listen() once
then in a loop:
call accept(), this call will block until a client connects, and then return a connected socket,
do whatever you need to do with that (connected client) socket
resume with the loop

recvfrom infinite receiving problem

I m writing a server using udp socket. After a client send first message to connect, i open new socket to communicate with this client on this socket (first sockets for listening) and create a thread for each client. But in thread, the while loop goes infinitely because recvfrom receive data everytime altough any client send data. What is the problem in my code?
The code sample below:
int main()
{
.....
// creating socket
if( (sock = socket(AF_INET, SOCK_DGRAM, 0) ) == -1 )
{
perror("Socket cannot be created\n");
return FAILURE;
}
.....
for(; ;)
{
// TAKE CLIENTS INFORMATION
/**************************************/
recvfrom(sock, &client, sizeof(Client), MSG_WAITALL, (struct sockaddr *)&clientAddr, &size); //1
.......
if( (sock2 = socket(AF_INET, SOCK_DGRAM, 0) ) == -1 )
{
perror("Socket cannot be created\n");
return FAILURE;
}
client.sock = sock2;
...
pthread_create(thid+num_client-1, NULL, messanger, (void*)(clients + num_client-1));
} // end of for loop
}// end of main
// thread function
void *messanger(void *argClient)
{
Client client = *(Client*)argClient;
...
while(strcmp(message.buffer, "exit") != 0)
{
recvfrom(client.sock, &message, sizeof(Message), MSG_WAITALL, (struct sockaddr *)&clientAddr, &size);
printf("%s\n", message.buffer);
}// this file loops infinetely altough client does not send data. Printf prints onln new line
}
Where do you bind() the second socket (or the first, for that matter)? Why aren't you checking recvfrom() for failure?
This isn't the way to write a UDP server, anyway. You use a single socket to recieve all packets. You then inspect the sender address, match it up with the right client and handle it as appropriate (for example, you could put it onto a work queue for a per-client thread, then wake that thread up using pthread_cond_signal()).
You're busy-waiting. Try using poll or select instead.

Resources