After looking at Beej's guide to network programming, I am trying to redo my server.c using select instead of fork. I am not too sure what is going wrong; my program compiles, but doesn't accept connections. I know that my loop containing i<=fdmax isn't functioning properly, but I can't figure out why. It seems like the if statements are not working appropriately.
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/select.h>
#define Connections 5
void SignalCatcher(int signum)
{
wait3(NULL,WNOHANG, NULL);
//wait(-1);
}
int main(int argc, char**argv)
{
int listenfd,connfd,n, i;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
pid_t childpid;
char mesg[1000];
FILE *inputFile;
inputFile = fopen("movie.txt", "r");
char returnMsg[1000];
int fdmax, newfd;
fd_set readfd;
fd_set mastersocket;
FD_ZERO(&mastersocket);
FD_ZERO(&readfd);
//Creating socket number
listenfd=socket(AF_INET,SOCK_STREAM,0);
//Setting up the internet address
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
//Listening for clients
listen(listenfd,1024);
FD_SET(listenfd, &mastersocket);
fdmax=listenfd;
//signal(SIGCHLD, SIG_IGN);
signal(SIGCHLD, SignalCatcher);
//Infinite loop that waits for/accepts connections.
for(;;)
{
readfd = mastersocket;
clilen=sizeof(cliaddr);
if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);}
//connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
for(i=0; i<=fdmax;i++)
{
if (FD_ISSET(i, &readfd)){
if(i==listenfd){
printf("-SUCCESS\n");
clilen = sizeof cliaddr;
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); }
if (connfd!=-1)
{
// if ((childpid = fork()) == 0)
// {
close (listenfd);
for(;;)
{
n = recvfrom(connfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
if (n == -1 /*&& errno == EWOULDBLOCK*/) continue;
else if(n==0) break;
//sendto(connfd,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
//write(connfd , mesg , strlen(mesg)); //both work
//write(connfd , "" , 1);
printf("-------------------------------------------------------\n");
printf("%d",listenfd);
mesg[n] = 0;
printf("Received the following:\n");
printf("%s",mesg);
printf("-------------------------------------------------------\n");
}
// }
close(connfd);
} //if connfd!=-1
}
} //for i<=fdmax
}
}
You can answer this question yourself by examining the functions' return values. In network programming, the usual idiom is something along the lines of:
if (foo() < 0) {
fprintf(stderr, "foo: %s\n", strerror(errno));
/* recover from error or... */
exit(EXIT_FAILURE);
}
...where foo() is one of bind(), listen(), accept(), send*/recv*() and so on.
Go ahead and try. errno will tell you what's wrong.
Besides, it's unclear why you are using select() at all. All you do is listen on a single socket, and you close it as soon as someone connects. Instead, you could just accept(listenfd).
firstly you should not close the listening fd it should be close while exiting the program. secondly we need to accept all incoming connections that are queued up on the listening socket.then if listening socket is not readable then an existing connection must be readable, so read the data for that connection. I just read once but u can read in loop for that connection until recv fails.
following code change should work:
//Infinite loop that waits for/accepts connections.
for(;;)
{
readfd = mastersocket;
clilen=sizeof(cliaddr);
if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);}
//connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
for(i=0; i<=fdmax;i++)
{
if (FD_ISSET(i, &readfd)){
if(i==listenfd){
printf("-SUCCESS\n");
clilen = sizeof cliaddr;
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
if (connfd!=-1)
{
FD_SET(connfd, &mastersocket);
if (connfd > fdmax) {
fdmax = connfd;
}
}
}
else
{
n = recvfrom(i,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
if ((n == -1 /*&& errno == EWOULDBLOCK*/) || (n==0)) {
close (i);
FD_CLR (i, &mastersocket);
if (i == fdmax)
{
while (FD_ISSET(fdmax, &mastersocket) == 0)
fdmax -= 1;
}
}
//sendto(i,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
//write(i , mesg , strlen(mesg)); //both work
//write(i , "" , 1);
printf("-------------------------------------------------------\n");
printf("%d",listenfd);
mesg[n] = 0;
printf("Received the following:\n");
printf("%s",mesg);
printf("-------------------------------------------------------\n");
}
}
} //for i<=fdmax
}
I tried your code with changes and its working fine to me.
Also if you want only one client communicate with server at a time then enable the while loop for reading client data.
server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/select.h>
#define Connections 5
void SignalCatcher(int signum)
{
wait3(NULL,WNOHANG, NULL);
//wait(-1);
}
int main(int argc, char**argv)
{
int listenfd,connfd,n, i;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
pid_t childpid;
char mesg[1000];
FILE *inputFile;
inputFile = fopen("movie.txt", "r");
char returnMsg[1000];
int fdmax, newfd;
fd_set readfd;
fd_set mastersocket;
FD_ZERO(&mastersocket);
FD_ZERO(&readfd);
//Creating socket number
listenfd=socket(AF_INET,SOCK_STREAM,0);
//Setting up the internet address
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
//Listening for clients
listen(listenfd,1024);
FD_SET(listenfd, &mastersocket);
fdmax=listenfd;
//signal(SIGCHLD, SIG_IGN);
signal(SIGCHLD, SignalCatcher);
//Infinite loop that waits for accepts connections.
for(;;)
{
readfd = mastersocket;
clilen=sizeof(cliaddr);
if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);}
//connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
for(i=0; i<=fdmax;i++)
{
if (FD_ISSET(i, &readfd)){
if(i==listenfd){
printf("-SUCCESS\n");
clilen = sizeof cliaddr;
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
if (connfd!=-1)
{
FD_SET(connfd, &mastersocket);
if (connfd > fdmax) {
fdmax = connfd;
}
}
}
else
{
//while(1) {
n = recvfrom(i,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
if ((n == -1 /*&& errno == EWOULDBLOCK*/) || (n==0)) {
close (i);
FD_CLR (i, &mastersocket);
if (i == fdmax)
{
while (FD_ISSET(fdmax, &mastersocket) == 0)
fdmax -= 1;
}
// break;
}
//sendto(i,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
//write(i , mesg , strlen(mesg)); //both work
//write(i , "" , 1);
printf("-------------------------------------------------------\n");
printf("%d",listenfd);
mesg[n] = 0;
printf("Received the following:\n");
printf("%s",mesg);
printf("-------------------------------------------------------\n");
}
//} /* end of while */
}
} //for i<=fdmax
}
}
client.c
#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>
#define SERVER_PORT 32000
int main (int argc, char *argv[]) {
int sd, rc, i;
struct sockaddr_in localAddr, servAddr;
struct hostent *h;
char message[1000] ;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons( SERVER_PORT );
/* create socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd<0) {
perror("cannot open socket ");
exit(1);
}
/* bind any port number */
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = htons(0);
rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
if(rc<0) {
printf("%s: cannot bind port TCP %u\n",argv[0],SERVER_PORT);
perror("error ");
exit(1);
}
/* connect to server */
rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
if(rc<0) {
perror("cannot connect ");
exit(1);
}
while(1)
{
printf("Enter message : ");
scanf("%s" , message);
rc = send(sd, message, strlen(message) + 1, 0);
if(rc<0) {
perror("cannot send data ");
close(sd);
exit(1);
}
printf("To_server: data%u sent (%s)\n",strlen(message),message);
}
return 0;
}
Related
I have a problem about the recv() function.
When I sent the first message(ex: hi) to server first, the server would send back the same message to client.
And I sent again(ex: hi2), I would get a null message.
But I kept sending message,maybe I sent two times again. I got the second message I sent.
I want the result is client send to server and client receive the right message immediately.
How can I solve this problem?
my client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc , char *argv[])
{
int sockFD = 0;
sockFD = socket(AF_INET , SOCK_STREAM , 0);
if (sockFD == -1){
printf("Fail to create a socket.");
}
struct sockaddr_in info;
bzero(&info,sizeof(info));
info.sin_family = PF_INET;
info.sin_addr.s_addr = inet_addr("127.0.0.1");
info.sin_port = htons(8080);
if(connect(sockFD,(struct sockaddr *)&info,sizeof(info)) == -1){
perror("connect()");
}
char receiveMessage[100] = {};
memset(receiveMessage, 0, sizeof(receiveMessage));
char* input;
while(scanf("%s", input) == 1){
if(strcmp("exit", input) == 0){
break;
}
if(send(sockFD, input, sizeof(input), 0) < 0){
perror("send()");
}
if(recv(sockFD, receiveMessage, sizeof(receiveMessage), 0) < 0){
perror("recv()");
}
printf("Server: %s\n",receiveMessage);
}
printf("close Socket\n");
close(sockFD);
return 0;
}
my server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main()
{
int sockFD = 0, clientSockFD= 0;
char inputBuffer[256] = {};
//char outputBuffer[256] = {};
fd_set masterFD;
fd_set readFD;
int fdMax;
// create socket
sockFD = socket(AF_INET, SOCK_STREAM, 0);
if(sockFD == -1){
perror("socket()");
exit(0);
}
struct sockaddr_in serverInfo, clientInfo;
int addrLen = sizeof(clientInfo);
bzero(&serverInfo, sizeof(serverInfo));
serverInfo.sin_family = PF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(8080);
// bind port
if(bind(sockFD, (struct sockaddr *)&serverInfo, sizeof(serverInfo))){
perror("bind()");
}
// listen
if(listen(sockFD, 10)){
perror("listen()");
}
FD_SET(sockFD, &masterFD);
fdMax = sockFD;
while(1){
readFD = masterFD;
if(select(fdMax + 1, &readFD, NULL, NULL, NULL) == -1){
perror("select()");
exit(0);
}
for(int i = 0; i <= fdMax; i++){
if(FD_ISSET(i, &readFD)){
if(i == sockFD){
if((clientSockFD = accept(sockFD, (struct sockaddr *)&clientInfo, &addrLen)) < 0){
perror("accept()");
}
FD_SET(clientSockFD, &masterFD);
if(clientSockFD > fdMax){
fdMax = clientSockFD;
}
printf("selectserver: new connection\n");
}
else{
int recvStatus = recv(i, inputBuffer, sizeof(inputBuffer), 0);
if(recvStatus <= 0){
if(recvStatus < 0){perror("recv()");}
else if(recvStatus = 0){printf("colse connected");}
close(i);
FD_CLR(i, &masterFD);
}
else{
printf("client: %s\n", inputBuffer);
send(i, inputBuffer, sizeof(inputBuffer), 0);
}
}
}
}
}
return 0;
}
Change
send(i, inputBuffer, sizeof(inputBuffer), 0);
Into:
send(i, inputBuffer,recvStatus , 0);
The cause: you were sending a complete buffer, containing only a few intended characters, but padded (upto size=256) with NULs, (or whatever garbage is the buffer from previous calls))
recv() and read() return the number of characters received. (or 0 on EOF,or -1 on errors (some of which could be handled, for instance: EAGAIN, EINTR))
I want to create a simple multithreaded chat application in C using api. For the beginning, i wrote a simple server communicating with client but there is a problem in the order messages sent.
example output:
in server
*new_sock socket number: 4
Server:hello client
Client:hello server
Server:how are you?
Client:
Server:
in client
Server:hello client
Client:hello server
Server:how are you?
Client:
//server code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <pthread.h>
void* connection_handler(void* socket_descriptor)
{
int socket = *(int *)socket_descriptor;
int n;
char server_buffer[256];
memset(server_buffer, 0, sizeof(server_buffer));
printf("Server:");
gets(server_buffer);
send(socket, server_buffer, strlen(server_buffer), 0);
memset(server_buffer, 0, sizeof(server_buffer));
while ((n = recv(socket, server_buffer, 255, 0)) > 0)
{
server_buffer[n] = '\0';
printf("Client:%s\n", server_buffer);
memset(server_buffer, 0, sizeof(server_buffer));
printf("Server:");
gets(server_buffer);
send(socket, server_buffer, strlen(server_buffer), 0);
memset(server_buffer, 0, sizeof(server_buffer));
n = 0;
}
close(socket);
free(socket_descriptor);
return 0;
}
int main(int argc, char *argv[])
{
int server_sock, client_sock, portno, client_len, n;
int *new_sock;
struct sockaddr_in server_addr, client_addr;
if(argc < 2)
{
printf("ERROR: no port provided.\n");
exit(1);
}
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if(server_sock < 0)
{
printf("ERROR: opening socket.");
exit(1);
}
portno = atoi(argv[1]);
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portno);
server_addr.sin_addr.s_addr = INADDR_ANY;
if( bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0 )
{
printf("ERROR: binding socket.");
exit(1);
}
listen(server_sock, 5);
pthread_t handler_thread;
while( client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len) )
{
new_sock = malloc(sizeof(int));
*new_sock = client_sock;
printf("*new_sock socket number: %d\n", *new_sock);
if( pthread_create(&handler_thread, (void *)NULL, connection_handler, (void *)new_sock) < 0)
{
printf("ERROR: creating thread\n");
exit(1);
}
}
pthread_join(handler_thread, NULL);
printf("server shut down.\n");
return 0;
}
//client code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main(int argc, char* argv[])
{
int sock_descriptor, portno, n;
struct sockaddr_in server_addr;
char buffer[256];
if (argc != 2)
{
printf("usage: %s port\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);
sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
if (sock_descriptor < 0)
{
printf("ERROR: creating socket!\n");
exit(1);
}
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(portno);
if (connect(sock_descriptor, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("ERROR: connecting server!\n");
exit(1);
}
memset(buffer, 0, sizeof(buffer));
while((n = recv(sock_descriptor, buffer, 255, 0)) > 0)
{
buffer[n] = '\0';
printf("Server:%s\n", buffer);
memset(buffer, 0, sizeof(buffer));
printf("Client:");
gets(buffer);
send(sock_descriptor, buffer, sizeof(buffer), 0);
memset(buffer, 0, sizeof(buffer));
}
if (n <= 0)
{
printf("ERROR: reading from socket");
exit(1);
}
return 0;
}
Join the threads right after it has been created , accept is a blocking call (I assume you have not modified the default behavior) . Threads are complex to analyze however , the call to join wont even come since blocking accept call in while loop.
while(1)
{
//do something here
...
if( pthread_create(&handler_thread, (void *)NULL, connection_handler, (void *)new_sock) < 0)
{
printf("ERROR: creating thread\n");
exit(1);
}
pthread_join(handler_thread, NULL); //Use it right after creating thread
}
I wrote a simple TCP echo server to handle multiple clients. It uses select() to get multiple connections.
Server Code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int create_listener(uint16_t port) {
int listen_fd;
struct sockaddr_in name;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror ("socket");
exit(EXIT_FAILURE);
}
bzero(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror ("bind");
exit(EXIT_FAILURE);
}
return listen_fd;
}
int read_from_client(int fd) {
char buffer[100];
int nbytes;
nbytes = read(fd, buffer, 100);
if (nbytes < 0) {
perror("read");
exit(EXIT_FAILURE);
}
else if (nbytes == 0) {
return -1;
}
else {
fprintf(stderr, "Server: got message: %s\n", buffer);
write(fd, buffer, strlen(buffer) + 1);
return 0;
}
}
int main(int argc, char *argv[]) {
int listen_fd;
uint16_t port = 22000;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in servaddr;
/* Create the socket and set it up to accept connections. */
listen_fd = create_listener(port);
if (listen(listen_fd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO(&active_fd_set);
FD_SET(listen_fd, &active_fd_set);
while (1) {
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, 0) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET(i, &read_fd_set)) {
if (i == listen_fd) {
/* Connection request on original socket. */
int new_fd;
new_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (new_fd < 0) {
perror ("accept");
exit(EXIT_FAILURE);
}
FD_SET(new_fd, &active_fd_set);
}
else {
/* Data arriving on an already-connected socket. */
if (read_from_client(i) < 0) {
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
return 0;
}
Client code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, n;
char sendline[100];
char recvline[100];
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22000);
inet_pton(AF_INET, "127.0.0.1", &(servaddr.sin_addr));
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (1) {
bzero(sendline, 100);
bzero(recvline, 100);
fgets(sendline, 100, stdin);
write(sockfd, sendline, strlen(sendline) + 1);
read(sockfd, recvline, 100);
printf("%s", recvline);
}
return 0;
}
The problem is when I run server in one terminal and run two clients in another two terminals. If I use Ctrl+C to terminate one client, the server automatically terminates. I'm wondering why the server acts this way. What I'm expecting is the server runs forever. When client 1 terminates, server should still has a live connection with client 2.
Looks like you're hitting the exit in read_from_client. In general, in a server that serves multiple clients, you probably don't want to exit when you have a failure with one of the client connections.
I'm making a client-server program in C using threads.
I've got this problem: on the server, on thread #1 (number_one), function "read" works fine. But when I create another thread #2 (number_two), on this one something goes wrong. Parameters are passed in the right way (I think).
-->thread number_one
...
char message[256];
int new_connection=accept(master_sock,NULL,NULL);
pthread_t temp
if(pthread_create(&temp , NULL , number_two , (void*) &new_connection))
{
perror("pthread_create failed");
exit(-2);
}
else
{
puts("number_two created");
if(read(new_connection, message, 256) > 0)
printf("Message from client is %s", message);
}
if(pthread_detach(temp))
{
perror("detach failed");
exit(-3);
}
...
---> thread number_two
void *number_two(void *sock_desc)
{
int sock = *(int*)sock_desc;
int read_size;
char client_message[2000];
read_size=read(sock, client_message, 256);
client_message[read_size]='\0';
return 0;
}
In "number_one", read waits an input from the client, and then it sets correctly the buffer "message".
In "number_two", read does not wait the client and does not set the buffer "client_message".
Thank you.
Please try my code? it works, I think it is the same with your code.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#define INVALID_SOCKET_FD (-1)
int create_tcp_server_socket(unsigned short port, bool bind_local, int backlog,
char *caller_name)
{
int socket_fd = INVALID_SOCKET_FD;
struct sockaddr_storage server_addr;
unsigned int yes = 1;
// just try ipv4
if (socket_fd < 0 && (socket_fd = socket(PF_INET, SOCK_STREAM, 0)) >= 0) {
struct sockaddr_in *s4 = (struct sockaddr_in *)&server_addr;
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
memset(&server_addr, 0, sizeof(server_addr));
s4->sin_family = AF_INET;
s4->sin_port = htons(port);
if (bind_local)
s4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
s4->sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(socket_fd, (struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
close(socket_fd);
printf("Server: Failed to bind ipv4 server socket.\n");
return INVALID_SOCKET_FD;
}
}
else if (socket_fd < 0) {
printf("Server: Failed to create server socket.\n");
return INVALID_SOCKET_FD;
}
if (listen(socket_fd, backlog) < 0) {
close(socket_fd);
printf("Server: Failed to set listen.\n");
return INVALID_SOCKET_FD;
}
return socket_fd;
}
pthread_t temp;
void *number_two(void *sock)
{
char buf[1024];
int fd = *(int *)sock;
int nread = read(fd, buf, 1024);
write(STDOUT_FILENO, buf, nread);
return NULL;
}
int main()
{
pid_t pid;
if ((pid = fork()) < 0) {
}
else if (pid > 0) { // parent, server
char buf[1024];
int fd = create_tcp_server_socket(8787, false, 10, "zz");
int new_fd = accept(fd, NULL, 0);
pthread_create(&temp, NULL, number_two, (void *)&new_fd);
}
else { // child, client
uint32_t ip;
struct hostent *hp = gethostbyname("localhost");
memcpy(&ip, hp->h_addr_list[0], hp->h_length);
struct sockaddr_in server_addr;
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = ip;
server_addr.sin_port = htons(8787);
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
write(fd, "abcd", 4);
}
pause();
return 0;
}
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.