I have a server daemon listening on a TCP unix domain/local socket. Multiple clients running on the same machine connect to it. The daemon is also bound to a UDP Internet socket. Whenever the daemon receives any data from one of the local clients, it sends the same data to all the connected clients except the sending client. If the daemon receives data on the UDP internet socket, it needs to send that data to all the local connected clients. The sending/receiving of data works perfectly when the daemon receives data on the local socket. However, the clients do not receive any data when the server sends them data received on the UDP internet socket. The clients receive that internet data either after the server daemon is exited and the connection is closed, or, when any of the clients sends data locally to the server. The internet data is received by the clients along with the local data. I have set both local and inet sockets as blocking using fcntl(). Here is the daemon code that I have (I have removed all the unnecessary code):
while(1)
{
FD_SET(sockfd, &read_fds);
FD_SET(inet_sock, &read_fds);
for (i = 0; i < nclients; i++)
{
FD_SET(clients[i], &read_fds);
}
select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL);
/* Check for events on inet sock */
if (FD_ISSET(inet_sock, &read_fds))
{
/* Read from inet sock */
socklen = sizeof(dest_sin);
rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT,
(struct sockaddr *) &dest_sin, &socklen);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
}
}
/* A read event on the local socket is a new connection */
if (FD_ISSET(sockfd, &read_fds))
{
socklen = sizeof(dest_sun);
/* Accept the new connection */
rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen);
/* Add client to list of clients */
clients[nclients++] = rval;
if (rval > maxfd) maxfd = rval;
snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0",
nclients, rval);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
}
/* Check for events from each client */
for (i = 0; i < nclients; i++)
{
fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]);
/* Client read events */
if (FD_ISSET(clients[i], &read_fds))
{
fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]);
/* Read from client */
rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
/* Skip the sender */
if (j == i) continue;
/* Send the message */
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
}
}
}
}
Here is the client code that I have:
while(1)
{
FD_SET(fileno(stdin), &read_fds);
FD_SET(sockfd, &read_fds);
select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1,
&read_fds, &write_fds, &except_fds, NULL);
if (FD_ISSET(sockfd, &read_fds))
{
/* Read from socket and display to user */
mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT);
buf[mlen]=0;
printf("Received %d bytes: %s", mlen, buf);
}
if (FD_ISSET(fileno(stdin), &read_fds))
{
fgets(buf, BUFLEN, stdin);
fprintf(stderr, "Sent %d octets to server.",
send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0));
}
}
The goal is to have the clients receive data immediately that the daemon sends them (the data which the daemon receives on its inet socket).
EDIT: I have figured that when the daemon sends the data, the select() on the client side returns that the socket is readable, but recv() is blocking, that's the reason I'm not getting data on the client side. Any suggestions on how to fix this?
Here's the send() calls from your code, extracted and aligned:
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
I see some inconsistencies here. Sometimes you call strlen(), sometimes strnlen(), and sometimes strlen() with two arguments (I don't even know what that's going to do).
The problem you're seeing may be related to the fact that you're not sending any information on the socket that shows where the boundaries between messages are. Over a stream socket, message boundaries are not preserved and you should take care to include appropriate framing information in your protocol so that the receiver can extract the individual messages. You cannot rely on exactly the same number of bytes coming through a recv() call as there was in a send() call. You will get the same total number of bytes in the same order (that's the point of a stream socket), but the messages might get consolidated or split up and you have no control over that.
Related
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.
I tried to learn about the conception of Socket-Send(Receive)-Buffer.And I wrote these codes:
Client:
int client = socket(AF_INET, SOCK_STREAM, 0);
int s = getsockopt(client, SOL_SOCKET, SO_SNDBUF, &sendBuffSize, &len);
int status = connect(client, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
printf("The send buff size is : %d.\n", sendBuffSize);
char buf[100000];
int n, wn;
int fd = open("./1.txt", O_RDONLY);
while ((n = read(fd, buf, sizeof(buf))) > 0) {
wn = write(client, buf, n);
printf("Write %d bytes.\n", wn);
}
Server: I set the connected client as Non-block,and add this client into the epoll.Once the client sends data to the server, I put the main thread into sleep[ten seconds].
char buf[8192];
sleep(10);
int rn;
while ((rn = read(events[i].data.fd, buf, sizeof(buf))) > 0) {
printf("Read %d bytes.\n", rn);
}
The client send Buffer size is 16384 and the server receive Buffer size is 20000[setsockopt].
According to the book:The client calls the write function will block if the socket send buffer is full.
But I get the result[Client] :
Result
And the server :
Result
Questions:
Receive buffer size + Send buffer size < 100000; but why the write function do not block?
Why the server read 8192 + 6808 = 15000 bytes instead of read continuously 8192 bytes?
There is no evidence here that the client writes did not block. On the contrary, the fact that all the writes were 100,000 bytes except the last, when you ran out of input, shows that it must have blocked, to transfer all that data into a socket buffer that is smaller.
TCP segmentizes, and IP packetises, the data sent over the wire. You have no control over that process. In any case a read() can transfer any amount of bytes from 1 up to the count supplied, or zero upwards in non-blocking mode. It is a streaming protocol, not a messaging protocol. There is no other guarantee about how much any individual read() will return at a time.
I'm writing a sender-receiver protocol with ACKs in C. Whenever the sender sends a packet, the receiver will send a correspondant ACK and then wait for the next packet. The problem is that since I'm testing everything on the same machine (using 127.0.0.1 as address) the receiver will receive its own ACKs in an infinite loop. What am I doing wrong?
Here's the code from the receiver side (all inside a while loop):
if ((recvfrom(sockfd, buff, PACKETSZ + 1, 0, (struct sockaddr *) &sndaddr, &len)) < 0) {
perror("recvfrom");
return -1;
}
fprintf(stderr, "Packet received: '%s'.\n", buff);
// Get sequence number (seqn) from the packet
char answer[PACKETSZ];
snprintf(answer, PACKETSZ, "%d-ACK", seqn);
printf("Sending '%s'\n", answer);
if (sendto(sockfd, answer, strlen(answer) + 1, 0, (struct sockaddr *) &sndaddr, sizeof(sndaddr)) < 0) {
perror("sendto");
return -1;
}
How can I prevent a process from receiving the datagrams being sent by itself?
I don't think you can keep the socket from receiving the message in this situation, rather you need to use the address parameter to recvfrom and ignore the message if it came from your own socket.
I am trying to send a file from client to the server using C socket programming. but in the server side I am not able to receive the file which I had sent from the client. I am attaching the codes below.
server:
/* Create a connection queue and wait for clients. */
listen(server_sockfd, 5);
while(1) {
char ch;
printf("server waiting\n");
/* Accept a connection. */
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr*)&client_address,cli);
if(client_sockfd > 0)
printf("client is connected\n");
/* We can now read/write to client on client_sockfd. */
char *fh;
recv(client_sockfd,fh,1024+1,0);
printf("server recieved %s",fh);
/* read(client_sockfd, &ch, 1);
ch++;
write(client_sockfd, &ch, 1); */
return close(client_sockfd);
}
}
You need to check the return of recv
if ((nbytes = recv(client_sockfd,fh,1024+1,0)) > 0)
and end your buffer with '\0'
fh[nbytes] = '\0';
printf("server recieved %s",fh);
Also, is not a good idea to use magic numbers like 1024+1
RFC 793 says that TCP defines a "push" function that ensures that the receiver got the data:
Sometimes users need to be sure that all the data they have
submitted to the TCP has been transmitted. For this purpose a push
function is defined. To assure that data submitted to a TCP is
actually transmitted the sending user indicates that it should be
pushed through to the receiving user. A push causes the TCPs to
promptly forward and deliver data up to that point to the receiver.
However, I can't find a push system call. Using fsync on the file descriptor produces an invalid argument error.
I conducted an experiment with a simple server that accepts a connection from a client, waits, then sends 26 bytes to the client:
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1234
int main(void)
{
int server_fd;
int client_fd;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
perror("bind");
return 1;
}
}
if (listen(server_fd, 20) != 0) {
perror("listen");
return 1;
}
{
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
printf("Waiting for connection on port %d\n", PORT);
if ((client_fd = accept(server_fd, (struct sockaddr*)&addr, &addrlen)) < 0) {
perror("accept");
return 1;
}
printf("%s:%d connected\n",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
}
printf("Giving client time to close connection.\n");
sleep(10);
{
ssize_t sent_length;
if ((sent_length =
send(client_fd, "abcdefghijklmnopqrstuvwxyz", 26, 0)) < 0)
{
perror("send");
return 1;
}
printf("Sent %Zd bytes.\n", sent_length);
}
printf("Closing connection to client\n");
if (close(client_fd) != 0) {
perror("close(client_fd)");
return 1;
}
printf("Shutting down\n");
if (close(server_fd) != 0) {
perror("server: close(server_fd)");
return 1;
}
printf("Done!\n");
return 0;
}
I found that the send call immediately returns 26, even after I close the connection client-side or unplug the network cable. In the latter case, the data appears on the client when I plug the cable back in and wait a few seconds (long after the server has shut down).
How do I ensure that data sent with send is received and acknowledged?
There is no push, says the late W. Richard Stevens; the standard sockets API doesn't provide it, and is not required to do so by RFC 1122. You can set the TCP_NODELAY option, but that's only a partial solution.
If you want to be sure the other end got your data, then let it send an acknowledgment over the TCP channel.
try to add a shutdown call before the close of the socket;
shutdown(client_fd,SHUT_RDWR);
However the real solution is to get an acknowledgement back from the client that it has received the data -- I.e. you need to define a protocol -- the simplest of simple protocols is that the client is responsible for closing the socket when the data is received.
Well as per my limited knowledge, TCP will insure that the data is transferred to the other machine / socket.
But has the program at the other end read / accessed the data cannot be confirmed using standard socket API's. Your other end (client in this case) might be busy doing something else instead of waiting for data to show up.
I think that your requirement will be full filled if you implement some sort of handshaking between server / client to track what all has been received using some kind of acknowledgements.
The acknowledgement mechanism is important if your application depends on it.
You can force immediately sending of small packets by disabling Nagle's algorithm, but this does not guarantee that the client will receive it.
If you have to wait for the acknowledge you have to build this into the protocol and wait for the client to write something into the socket that signals the reception of message.
The only way to make sure your data is send over is to Receive an answer. After testing for many days this is the only way to make sure it is 'flushed' to the other side.
// Receive until the peer closes the connection to make sure all data has been send
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0){
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0){
printf("Connection closed\n");
}
else{
printf("recv failed with error: %d\n", WSAGetLastError());
}
} while (iResult > 0);