writing to a close socket didn't raise a SIGPIPE as expected - c

I've already read about how to prevent SIGPIPE, then I write a small program to test it. Here is the code.
server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void hdl(int sig_num, siginfo_t *sig_info, void *context)
{
printf("got you, SIGPIPE!\n");
}
int main()
{
int sfd, cfd;
struct sockaddr_in saddr, caddr;
struct sigaction act;
memset (&act, '\0', sizeof(act));
act.sa_sigaction = hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGPIPE, &act, NULL) < 0) {
return 1;
}
sfd= socket(AF_INET, SOCK_STREAM, 0);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=inet_addr("192.168.22.91");
saddr.sin_port=htons(12345);
if(bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr)) )
{
printf("bind error\n");
return -1;
}
if(listen(sfd, 1))
{
printf("error\n");
return -1;
}
char buf[1024] = {0};
while(1) {
printf("Server listening...\n");
cfd=accept(sfd, (struct sockaddr *)NULL, NULL);
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
if((ret = write(cfd, buf, strlen(buf)))<0)
{
if(errno == EPIPE)
fprintf(stderr, "SIGPIPE");
}
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);
}
close(sfd);
}
client.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int ret, fd;
struct sockaddr_in sa_dst;
char buffer[] = "hello, world";
char rcv_buf[128] = {0};
fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(12345);
sa_dst.sin_addr.s_addr = inet_addr("192.168.22.91");
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
if(ret != -1)
{
send(fd, buffer, strlen(buffer), 0);
close(fd);
}
return 0;
}
When I run the server and the client on the same linux machine, on the server side, the first write() returns the number of bytes written while I expect a SIGPIPE signal because I closed the socket on the client side, the second write() does generate a SIGPIPE signal.
But when I ran the client on another linux machine or on a Windows machine(implement the same client with Winsock), I did't catch any SIGPIPE signal, and the second write() still returns the size of the buffer. Can someone tell me what's going on?

It can't happen on the first write, for two reasons:
The localhost doesn't know that the peer has closed the socket for reading. A FIN has been received but that could just be because the peer has shutdown for output. Only an RST will tell it that, and it doesn't get that util the next I/O at the earliest.
Buffering.
NB you're corrupting the value of errno by calling perror(), so testing it afterwards isn't valid.

Just Change this in SERVER and it will work
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
ret = write(cfd, buf, strlen(buf));
sleep(2);
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);

Related

C socket programming - write() from server writes to server instead of client

I'm working on a TCP client server program which is supposed to support several clients using threads.
The socket creation, connection, bind and accept work as expected since I receive no errors when running the code.
However whenever I try to read() from the server the code enters an infinite loop and nothing happens.
I tried writing from the server first and the write result was written to the server's terminal.
Client code:
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
int main(int argc, char *argv[]) {
//Get command line arguments
unsigned int port = atoi(argv[2]);
int length = atoi(argv[3]); //Number of bytes to read
char* buffer = malloc(length * sizeof(char)); //Buffer to hold data read from file
char* recvBuf = malloc(10 * sizeof(char)); // Buffer to hold response from server
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in serv_addr;
int sockfd = -1;
//int rv;
//char ip[100];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0) {
perror("getaddrinfo error\n");
exit(1);
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0)
continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0)
break;
close(sockfd);
sockfd = -1;
}
// inet_aton(ip, &h.sin_addr);
freeaddrinfo(servinfo);
//Open file for reading
FILE *fp;
fp = fopen(FILE_ADDR, "r");
if (fp == NULL) {
perror("Error in file open\n");
}
printf("file opened\n");
size_t numOfbytesRead = fread(buffer, sizeof(char), length, fp);
if (numOfbytesRead != length) {
perror("Error reading from file\n");
}
printf("Buffer is %s\n", buffer);
char* ptr;
unsigned int N = strtoul(argv[3],&ptr,10);
int convertedNum = htonl(N);
if (write(sockfd, &convertedNum, sizeof(unsigned int)) < 0) { //Send number of bytes
perror("error writing to socket");
}
if (write(sockfd, buffer, sizeof(buffer) < 0)) {//Send bytes read from file
perror("error writing to socket");
}
printf("send is done \n");
int bytes_read = read(sockfd, recvBuf, sizeof(recvBuf)); //Recieve response from server
if (bytes_read <= 0) {
perror("Error in recieving result from server\n");
}
unsigned int C = 0;
sprintf(recvBuf[0], "%d", C);
fclose(fp);
printf("# of printable characters: %u\n", C);
exit(0);
free(buffer);
free(recvBuf);
}
Server code:
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
static volatile int keepRunning = 1;
int pcc_total[159];
void intHandler(int dummy) {
keepRunning = 0;
}
void *compute(void *socket_desc) {
int count = 0;
int sock = *(int*) socket_desc;
printf("now will allocate N \n");
int n=0;
if (write(sock, "hi", 2) < 0) { //Send number of bytes
perror("error writing to socket\n");
}
if (read(sock, &n, sizeof(unsigned int)) < 0) {
perror("Error reading from socket\n");
exit(1);
}
int N = ntohl(n);
printf("len is %d\n", N);
char* data = calloc(N, sizeof(char));
int len = read(sock, data, N);
printf("data is %s\n", data);
if (len < 0) {
perror("Error reading from socket\n");
exit(1);
}
for (int i = 0; i < len; i++) {
int tmp = 0;
sprintf(data[i], "%d", tmp);
if (tmp >= 32 & tmp <= 126) {
count++;
__sync_fetch_and_add(&pcc_total[tmp], 1);
}
}
char scount[100];
atoi(count);
write(sock, count, strlen(scount));
free(data);
pthread_exit(NULL);
close(sock);
exit(0);
}
int main(int argc, char *argv[]) {
unsigned int port = atoi(argv[1]);
signal(SIGINT, intHandler);
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
c = sizeof(struct sockaddr_in);
socket_desc = socket( AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
perror("Could not create socket");
exit(1);
}
printf("socket created\n");
memset(&server, 0, c);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port);
if (0 != bind(socket_desc, (struct sockaddr*) &server, sizeof(server))) {
perror("\n Error : Bind Failed \n");
exit(1);
}
printf("bind created\n");
if (0 != listen(socket_desc, 10)) {
perror("\n Error : Listen Failed \n");
exit(1);
}
printf("listen created\n");
while (keepRunning) {
client_sock = accept(socket_desc, (struct sockaddr *) &client,
(socklen_t*) &c);
if (client_sock < 0) {
perror("\n Error : Accept Failed\n");
exit(1);
}
printf("accept created\n");
pthread_t tid;
new_sock = malloc(100*sizeof(int));
*new_sock = client_sock;
if ((pthread_create(&tid, NULL, compute, (void*) new_sock)) < 0) {
perror("could not create thread\n");
exit(1);
}
printf("thread created\n");
// close socket
close(client_sock);
free(new_sock);
pthread_join(tid, NULL);
}
exit(0);
}
I run the code with the following commands:
gcc -std=c99 -O3 -Wall -o pcc_server pcc_server.c -pthread
gcc -std=gnu99 -O3 -Wall -o pcc_client pcc_client.c
There are a number of problems with your code.
On the client side:
When calling fread(), you need to use "rb" instead of "r".
when calling printf() to output the file data that was actually read, you are not null-terminating buffer, or passing its length to printf(). You need to do so.
You are assigning the return value of htonl() to an int instead of an unsigned int.
when calling write() to send the buffer, you are using sizeof(buffer) when you should be using length or N instead (and why are you using two separate variables to hold the same command-line parameter value?). buffer is a pointer to memory allocated with malloc(), so sizeof(buffer) is the same as sizeof(void*), which is not what you want. Also, you are not even calling write() correctly, because your parenthesis are all wrong (they are correct on the previous write() call when sending convertedNum).
likewise, when calling read() to read the recvBuf, you are using sizeof(recvBuf) when you should be using 10 instead, sicne recvBuf is also a pointer to malloced memory.
you are not reading the "hi" greeting that the server sends to the client upon connection, so you lump in those bytes with the bytes of the following size value of the next message, and thus end up with a corrupted C value.
On the server side:
your compute thread routine sends a "hi" greeting to the client, but it does not use any kind of delimiter, like prefixing the greeting with its length, or terminating it with a line break or null character or other unique character, to separate it from any subsequent data. You should always delimit your messages in some manner.
you are closing the accepted socket and freeing the malloced new_sock as soon as you create a worker thread to handle that client. You are ripping away memory from behind the thread's proverbial back. The thread needs to be the one to close the socket and free the memory when it is done using them, not the accept loop.
The thread does attempt to close the socket (but not free the memory), but after it calls pthread_exit() first, which is wrong. pthread_exit() terminates the calling thread, so it needs to be the last thing that the thread calls (DO NOT call exit()!). In fact, don't even call pthread_exit() directly at all, just return from compute(), the pthreads library will then call pthread_exit() for you, passing it whatever void* value you choose to return.
your accept loop should not be calling pthread_join() at all. It blocks the calling thread until the specified thread terminates. That defeats the whole purpose of using threads to handle your clients, and prevents your server from accepting more than 1 client at a time. If you are going to use pthread_join() at all, it should be after the accept loop has ended, so you can wait for any worker threads that may still be running before exiting the app. But that also means keeping track of the pthread_t values that pthread_create() returns, which is more work.
With that said, try this code instead:
Client code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
char* readMsg(int sockfd, size_t *msgSize)
{
*msgSize = 0;
unsigned int length = 0;
int bytes_read = read(sockfd, &length, sizeof(length)); //Receive number of bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
return NULL;
}
length = ntohl(length);
char *buffer = malloc(length+1);
if (!buffer) {
perror("Error in allocating memory to receive message from server\n");
return NULL;
}
char *pbuf = buffer;
unsigned int buflen = length;
while (buflen > 0) {
bytes_read = read(sockfd, pbuf, buflen); // Receive bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
free(buffer);
return NULL;
}
pbuf += bytes_read;
buflen -= bytes_read;
}
*msgSize = length;
return buffer;
}
int sendMsg(int sockfd, char *msg, size_t msgSize)
{
unsigned int convertedNum = htonl(msgSize);
if (write(sockfd, &convertedNum, sizeof(convertedNum)) < 0) { //Send number of bytes
perror("error writing to socket");
return -1;
}
if (write(sockfd, msg, msgSize) < 0) { //Send bytes
perror("error writing to socket");
return -1;
}
return 0;
}
int main(int argc, char *argv[]) {
char* ptr;
//Get command line arguments
unsigned int port = atoi(argv[2]);
unsigned int length = strtoul(argv[3], &ptr, 10); //Number of bytes to read
char* buffer = malloc(length); //Buffer to hold data read from file
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in serv_addr;
int sockfd = -1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0) {
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0)
continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0)
break;
close(sockfd);
sockfd = -1;
}
freeaddrinfo(servinfo);
if (sockfd == -1) {
perror("socket create/connect error\n");
return 1;
}
size_t msgSize;
char *msg = readMsg(sockfd, &msgSize);
if (!msg) {
close(sockfd);
return 1;
}
printf("%.*s\n", (int)msgSize, msg);
free(msg);
//Open file for reading
FILE *fp = fopen(FILE_ADDR, "rb");
if (fp == NULL) {
perror("Error in file open\n");
close(sockfd);
return 1;
}
printf("file opened\n");
if (fread(buffer, 1, length, fp) != length) {
perror("Error reading from file\n");
fclose(fp);
close(sockfd);
return 1;
}
fclose(fp);
printf("Buffer is %.*s\n", (int)length, buffer);
if (sendMsg(sockfd, buffer, length) != 0) {
free(buffer);
close(sockfd);
return 1;
}
free(buffer);
printf("send is done \n");
msg = readMsg(sockfd, &msgSize); // response from server
if (!msg) {
close(sockfd);
return 1;
}
printf("# of printable characters: %.*s\n", (int)msgSize, msg);
free(msg);
return 0;
}
Server code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
static volatile int keepRunning = 1;
int pcc_total[159];
void intHandler(int dummy) {
keepRunning = 0;
}
char* readMsg(int sockfd, size_t *msgSize)
{
*msgSize = 0;
unsigned int length = 0;
int bytes_read = read(sockfd, &length, sizeof(length)); //Receive number of bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
return NULL;
}
length = ntohl(length);
char *buffer = malloc(length+1);
if (!buffer) {
perror("Error in allocating memory to receive message from server\n");
return NULL;
}
char *pbuf = buffer;
unsigned int buflen = length;
while (buflen > 0) {
bytes_read = read(sockfd, pbuf, buflen); // Receive bytes
if (bytes_read <= 0) {
perror("Error in receiving message from server\n");
free(buffer);
return NULL;
}
pbuf += bytes_read;
buflen -= bytes_read;
}
*msgSize = length;
return buffer;
}
int sendMsg(int sockfd, char *msg, size_t msgSize)
{
unsigned int convertedNum = htonl(msgSize);
if (write(sockfd, &convertedNum, sizeof(convertedNum)) < 0) { //Send number of bytes
perror("error writing to socket");
return -1;
}
if (write(sockfd, msg, msgSize) < 0) { //Send bytes
perror("error writing to socket");
return -1;
}
return 0;
}
void *compute(void *socket_desc) {
int sock = * (int*) socket_desc;
free(socket_desc);
if (sendMsg(sock, "hi", 2) != 0) {
perror("error writing to socket\n");
close(sock);
return NULL;
}
size_t length = 0;
char *data = readMsg(sock, &length);
if (!msg) {
close(sock);
return NULL;
}
printf("len is %d\n", (int)length);
printf("data is %.*s\n", (int)length, data);
int count = 0;
for (size_t i = 0; i < length; i++) {
// ...
}
free(data);
char scount[20];
sprintf(scount, "%d", count);
sendMsg(sock, scount, strlen(scount));
close(sock);
return NULL;
}
int main(int argc, char *argv[]) {
unsigned int port = atoi(argv[1]);
signal(SIGINT, intHandler);
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
socket_desc = socket( AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
perror("Could not create server socket");
return 1;
}
printf("server socket created\n");
memset(&server, 0, c);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(port);
if (bind(socket_desc, (struct sockaddr*) &server, sizeof(server)) < 0) {
perror("\n Error : Bind Failed \n");
close(socket_desc);
return 1;
}
printf("bind created\n");
if (listen(socket_desc, 10) < 0) {
perror("\n Error : Listen Failed \n");
close(socket_desc);
return 1;
}
printf("listening\n");
while (keepRunning) {
c = sizeof(client);
client_sock = accept(socket_desc, (struct sockaddr *) &client,
(socklen_t*) &c);
if (client_sock < 0) {
perror("\n Error : Accept Failed\n");
continue;
}
printf("client accepted\n");
new_sock = malloc(sizeof(int));
if (!new_sock) {
perror("\n Error : Malloc Failed\n");
close(client_sock);
continue;
}
*new_sock = client_sock;
pthread_t tid;
if (pthread_create(&tid, NULL, &compute, new_sock) != 0) {
perror("\n Error : Thread Create Failed\n");
free(new_sock);
close(client_sock);
continue;
}
printf("thread created\n");
}
close(socket_desc);
return 0;
}
I think you should remove the two lines
close(client_sock);
free(new_sock);
in the server code because the newly created thread can't perform on those variables and memory area if it is freed up at such an early point. Can you try the code again without it?
Your server closes the connected socket and frees the memory in which you stored its file handle immediately after launching the thread to handle that connection. You're unlucky that the server only hangs as a result, but you have data races, so formally your program's behavior is undefined.
Since the server isn't going to do anything else until the thread has finished, you might as well move the close() and free() after the pthread_join(). Or, considering that you do join before creating any other threads, how about just calling compute() synchronously instead of creating a new thread for it to run in?

C - Making UTP server/client chatroom with select()

I'm supposed to make the server broadcast the message it gets from a client to all the other clients connected.
The actual broadcast works, but I have no idea how to stop the clients from infinitely printing "[client]Received from friends:" when I CTRL+C the server,
OR
how to stop the Server from infinitely printing "[server]Message received..." when I CTRL+C any of the connected Clients. Or how to add a verification somewhere so that the Client will disconnect when trying to send the string "quit"
Maybe I'm asking for too much, but could someone please explain to me what exactly does select(..) do? I understand that it's monitoring the FDs, but I can't fully understand what's going on(step-by-step) after 1 second. Does it go through all FDs ,1 second for each then repeat? I kind of get the idea, but not entirely.
Thank you either way
SERVER
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define PORT 3050 //The port used by Clients
extern int errno;
char * conv_addr (struct sockaddr_in address)
{
static char str[25];
char port[7];
strcpy (str, inet_ntoa (address.sin_addr)); /* client IP */
bzero (port, 7); /* PORT */
sprintf (port, ":%d", ntohs (address.sin_port));
strcat (str, port);
return (str);
}
void Msgs(int fd,int sd,fd_set fds,int nr);
int main ()
{
struct sockaddr_in server_addr; /* struct for Server */
struct sockaddr_in client_addr; /* struct for Clients */
fd_set readfds; /* ready-to-read File Descriptors */
fd_set actfds; /* active/existant File Descriptors */
struct timeval tv; /* time thing, for select() */
int ServerSocketFD, ClientSocketFD; /* Socket descriptors */
int optval=1; /* ????*/
int fd; /* FD used to pass through all FDs */
int nfds; /* max number of FDs */
(ServerSocketFD = socket (AF_INET, SOCK_STREAM, 0));
setsockopt(ServerSocketFD, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
bzero (&server_addr, sizeof (server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl (INADDR_ANY);
server_addr.sin_port = htons (PORT);
bind (ServerSocketFD, (struct sockaddr *) &server_addr, sizeof(struct sockaddr) );
listen (ServerSocketFD, 5); //listen to maximum 5 clients,no more
FD_ZERO (&actfds);
FD_SET (ServerSocketFD, &actfds); /* Add the only existant one for now */
tv.tv_sec = 1; /* wait 1s */
tv.tv_usec = 0;
nfds = ServerSocketFD; /* max value of currently used FDs */
printf ("[server] Waiting at port :%d...\n", PORT);
fflush (stdout);
while (1) /* serve clients CONCURRENTLY */
{
bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds)); /* copy all existing FDs in actfds vector to the read-to-read-FDs vector */
select(nfds+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET (ServerSocketFD, &readfds)) /* if ServerSocket is ready to read stuff */
{
bzero (&client_addr, sizeof (client_addr));
int len = sizeof (client_addr);
ClientSocketFD = accept (ServerSocketFD, (struct sockaddr *) &client_addr, &len);
if (nfds < ClientSocketFD) /* adjust max FD, for select */
nfds = ClientSocketFD;
/* Add this accepted sockets' FD to the existing FDs */
FD_SET (ClientSocketFD, &actfds);
printf("[server] Client connected, with FD %d, from this address %s.\n",ClientSocketFD, conv_addr (client_addr));
fflush (stdout);
}
for (fd = 0; fd <= nfds; fd++) /* all FDs*/
{
if (fd != ServerSocketFD && FD_ISSET (fd, &readfds)) /* is a client ready to send/get messages? */
{
Msgs(fd,ServerSocketFD,actfds,nfds);
}
}
}
}
void Msgs(int fd,int ServerSocketFD,fd_set fds,int nrFD)
{
char buffer[100];
int bytes;
char msg[100];
bytes = read (fd, msg, sizeof (buffer));
/*
if(strstr(msg,"quit")!=0)
{
FD_CLR(fd, &fds);
close(fd);
exit(1);
}
*/
printf ("[server]Message received...%s\n", msg);
for(int i=0;i<=nrFD;i++)
{
if(i!=fd && i!=ServerSocketFD)
{
write (i, msg, bytes);
}
}
}
CLIENT
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
extern int errno;
int port;
int main (int argc, char *argv[])
{
int ClientSocketFD;
struct sockaddr_in server_addr;
char msg[100];
char reply[100];
if (argc != 3)
{
printf ("[client] Sintax: %s <server_address> <port>\n", argv[0]);
return -1;
}
port = atoi (argv[2]);
ClientSocketFD = socket (AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons (port);
connect(ClientSocketFD, (struct sockaddr *) &server_addr,sizeof (struct sockaddr));
int pid;
if((pid=fork())==-1)
{
perror("Error fork()");
exit(10);
}
if(pid==0) //CHILD
{
while(1)
{
bzero(msg,100);
printf ("[client]Send something to other clients: ");
fflush (stdout);
read (0, msg, 100);
if(strstr(msg,"quit")!=0)
{
break;
}
write (ClientSocketFD, msg, 100);
}
exit(7);
}
else if(pid > 0) //PARENT
{
while(1)
{
bzero(reply,100);
read (ClientSocketFD, reply, 100);
printf ("[client]Received from friends: %s\n", reply);
}
}
close (ClientSocketFD);
}
I have no idea how to stop the clients from infinitely printing "[client]Received from friends:" when I CTRL+C the server
read() returns 0 if the server terminates, so replace the while(1) loop in the client PARENT by
while (bzero(reply, 100), read(ClientSocketFD, reply, 100) > 0)
printf("[client]Received from friends: %.100s\n", reply);
kill(pid, SIGTERM); // terminate also the child
(and #include <signal.h>).
how to stop the Server from infinitely printing "[server]Message received..." when I CTRL+C any of the connected Clients
read() returns 0 if the client terminates, so call
Msgs(fd, ServerSocketFD, &actfds, nfds);
change the Msgs() type to
void Msgs(int fd, int ServerSocketFD, fd_set *fds, int nrFD)
and in Msgs() after bytes = read (fd, msg, sizeof (buffer)); add
if (bytes <= 0) { FD_CLR(fd, fds); close(fd); return; }
could someone please explain to me what exactly does select(..) do? I understand that it's monitoring the FDs, but I can't fully understand what's going on(step-by-step) after 1 second. Does it go through all FDs ,1 second for each then repeat?
As wildplasser noted in his comment, select() possibly changes the timeout argument to indicate how much time was left, so after 1 second without FD activity we may well end up with a zero timeout and a useless busy loop. We need a select() timeout only if we want to do something when none of the monitored FDs gets ready within a certain time, so in your case it's better to specify no timeout at all:
select(nfds+1, &readfds, NULL, NULL, NULL);

Socket operation on non-socket C

I am getting this error when trying to make an application to connect and listen to a port for data.
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char * arg[]){
int conn_s = socket(AF_INET, SOCK_STREAM, 0); //Create the socket
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1234);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int res = bind(conn_s, (struct sockaddr *) &servaddr, sizeof(servaddr));
if(res < 0){
printf("Error has occured\n");
}
FILE * stream = fdopen(conn_s, "w+"); //Create a stream for the socket
FILE * file = fopen("response2.txt", "w+"); //Create a file to store the output of the stream
char * line = NULL; //Where each line of the stream will be stored in
size_t len = 0; // The length of the line
ssize_t bytes; //The size of the line in bytes
int lis = listen(conn_s, SOMAXCONN);
fcntl(lis, F_SETFL, O_NONBLOCK);
while(1) {
conn_s = accept(lis, NULL, NULL);
if(conn_s < 0){
if((errno == EAGAIN) || (errno == EWOULDBLOCK))
continue;
perror("Failed to accept connection");
exit(EXIT_FAILURE);
}
long conn_s_flags = fcntl(conn_s, F_GETFL);
fcntl(conn_s, F_SETFL, conn_s_flags & ~O_NONBLOCK);
while((bytes = getline(&line, &len, stream)) != -1) {
printf("%s\n", line);
fwrite(line, sizeof(char), bytes, file);
}
close(conn_s);
}
free(line);
return 0;
}
I am trying to connect to port 1234, listen to it and accept it to recieve data, but the error keeps occuring.
Also I am trying to test using netcat, but get a different error whenever nc is running on the port I specified.
Thanks
int lis = listen(conn_s, SOMAXCONN);
fcntl(lis, F_SETFL, O_NONBLOCK);
while(1) {
conn_s = accept(lis, NULL, NULL);
listen() does not return a socket FD. It returns zero or -1. The second line is therefore erroneous, as is the following accept() call. It should be:
if (listen(conn_s, SOMAXCONN) == -1)
{
perror("listen");
return; // or whatever
}
fcntl(conn_s, F_SETFL, O_NONBLOCK);
while(1) {
int conn_c = accept(conn_s, NULL, NULL);
NB Don't lose conn_s by storing the result of accept() into it.

Program run not as I expected

I wonder why my program run but not as I expected. I'm making client-server using fork() but the result is : server2: success, but not listening as I want it. I compile it with gcc -o server2 server2.c
here is the server side :
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h> // trap the child exits and prevent zombies
#include <signal.h> // trap the child exits and prevent zombies
#include <stdlib.h>
// signal handler calls waitpid()
void sigchld_handler(int signo)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// declares variabel
int main(int argc, char *argv[])
{
struct sockaddr_in sAddr;
int listensock;
int newsock;
char buffer[25];
int result;
int nread;
int pid;
int val;
// create socket that will accept connection
listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// set our SO_REUSEADDR option
val = 1;
result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if(result < 0){
perror("server1 multiplexing");
return 0;
}
// bind to local port and all addresses associated with the machine
sAddr.sin_family = AF_INET;
sAddr.sin_port = htons(1972);
sAddr.sin_addr.s_addr = INADDR_ANY;
result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
if(result < 0){
perror("server2");
return 0;
}
// put the socket into listening mode for incoming connections
result = listen(listensock, 5);
if(result < 5){
perror("server2");
return 0;
}
// before start looping, we install our signal handler
signal(SIGCHLD, sigchld_handler);
// call accept() to block waiting for connection request from clients, after accept returns call fork() to create a new process
while(1){
newsock = accept(listensock, NULL, NULL);
if((pid = fork()) == 0){
// close listening socket, read char from client vice versa, close the socket and exit child process
printf("child process %i created.\n", getpid());
close(listensock);
nread = recv(newsock, buffer, 25, 0);
buffer[nread] = '\0';
printf("%s\n", buffer);
send(newsock, buffer, nread, 0);
close(newsock);
printf("child process %i finished.\n", getpid());
exit(0);
}else{
printf("child process error");
}
// parents process close
close(newsock);
}
}
and here is the client :
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
void child_func(int childnum);
// main function
int main(int argc, char *argv[])
{
int nchildren = 1;
int pid;
int x;
if (argc > 1){
nchildren = atoi(argv[1]);
}
for (x=0; x < nchildren; x++){
if((pid = fork() == 0)){
child_func(x+1);
exit(0);
}
}
wait(NULL);
return 0;
}
void child_func(int childnum){
int sock;
struct sockaddr_in sAddr;
char buffer[25];
// create client socket and bind it to local pprt
memset((void *) &sAddr, 0, sizeof(struct sockaddr_in));
sAddr.sin_family = AF_INET;
sAddr.sin_addr.s_addr = INADDR_ANY;
sAddr.sin_port = 0;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr));
// Attempt to connect to whichever server is running on the local machine
sAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sAddr.sin_port = htons(1972);
if (connect(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr)) != 0){
perror("client");
return;
}
// send some character to the server and insert sleep() function
snprintf(buffer, 128, "data from client #%i.", childnum);
sleep(1);
printf("child #%i sent %zu chars\n", childnum, send(sock, buffer, strlen(buffer), 0));
sleep(1);
printf("child #%i received %zu chars\n", childnum, recv(sock, buffer, 25, 0));
//close connection
sleep(1);
close(sock);
}
I think I know why you get the output
server2: success
and then why it exits.
It because of how you check for errors from the listen function. On error it returns -1 and on success it returns 0. Just like most other system calls. It does not return number you passed to it on success.
So the listen call succeeds and returns 0, but then you check for result < 5 and zero is indeed less than five, so you print the "error" and exit the program.

C echo server still echoes once after being terminated

I have written a simple echo server and a client in C.
Here is the server code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include "unp.h"
#define SERVER_PORT 10000
void start_echo_service(int connfd);
void SIGCHLD_handler(int signum);
int main()
{
int listenfd, connfd;
socklen_t len;
struct sockaddr_in server_addr, client_addr;
pid_t child_pid;
printf("***Starting the echo server***\n");
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Failed to create connection socket. Exiting...\n");
exit(0);
}
bzero(&server_addr, sizeof(struct sockaddr_in));
bzero(&client_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
if(bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
strerror(errno);
exit(0);
}
if(listen(listenfd, 1000) < 0)
{
strerror(errno);
exit(0);
}
/* Add the handler for SIGCHLD */
struct sigaction sigchld_action;
sigchld_action.sa_handler = SIGCHLD_handler;
sigemptyset(&sigchld_action.sa_mask);
sigchld_action.sa_flags = 0;
if(sigaction(SIGCHLD, &sigchld_action, NULL) < 0)
{
printf("Error while adding handler for SIGCHLD\n");
exit(0);
}
while(1)
{
len = sizeof(client_addr);
if((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &len)) < 0)
{
if(errno == EINTR)
continue;
else
{
strerror(errno);
exit(0);
}
}
child_pid = fork();
if(child_pid < 0)
{
//some error occured
strerror(errno);
exit(0);
}
else if(child_pid == 0)
{
// child process
close(listenfd);
start_echo_service(connfd);
close(connfd);
exit(1);
}
close(connfd);
}
close(connfd);
return 1;
}
void SIGCHLD_handler(int signum)
{
pid_t pid;
if((pid = waitpid(-1, NULL, 0)) > 0)
printf("Harvested child (pid): %d\n", pid);
}
void start_echo_service(int connfd)
{
char buf[256];
int bytes_read;
while(1)
{
if((bytes_read = read(connfd, buf, sizeof(buf))) > 0)
{
writen(connfd, buf, bytes_read);
continue;
}
else if(bytes_read == 0)
break;
else
{
if(errno == EINTR)
continue;
else
{
printf("Read error\n");
break;
}
}
}
}
Here is the client code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "unp.h"
#define SERVER_PORT 10000
void start_echo_client(int connfd);
int main(int argc, char *argv[])
{
int connfd;
struct sockaddr_in server_addr;
if(argc != 2)
{
printf("Usage: echo_client <server-address>\n");
exit(-1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], &(server_addr.sin_addr));
server_addr.sin_port = htons(SERVER_PORT);
if((connfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
strerror(errno);
exit(0);
}
if(connect(connfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
strerror(errno);
exit(0);
}
start_echo_client(connfd);
return 1;
}
void start_echo_client(int connfd)
{
char buffer[256];
while(fgets(buffer, sizeof(buffer), stdin) != NULL)
{
writen(connfd, buffer, strlen(buffer));
readn(connfd, buffer, strlen(buffer));
printf("%s", buffer);
}
}
I start my server with ./echo_server on one shell.
I start my client with ./echo_client 127.0.0.1 on another shell. So far, so good.
On my client, I type a message, say hello. The server echoes it back. Now, I terminate my server with Ctrl+C. The client is still running. Now, I type another message on the client, say zzz. I still get an echo back and zzz is printed on the shell. On typing another message on the client, it terminates.
I guess it may have something to do with the server being in uninterruptible sleep when I terminate it, but I can't be sure.
Here is the link to unp.h and unp.c
start_echo_client prints buffer irrespective of the return from readn, isn't? Even if server closed, buffer would contain contents of what happened with writen ( You use same buffer for write and read). Hence i think, you assume there was an echo from server while it was not.
The test with tcpdump as well indicates that FIN does arrive with ctrl-c on the server terminal. Client tries write ignoring the peer closure for which RST is received.
Also, read didn't yield zero on FIN. I changed to recv then the closure was caught.
Return the number of bytes read in the readn function instead what is being currently done and if its zero, then don't print buffer.

Resources