multithreading concept in client server program - c

my program only works as read operation for server and write operation for client side.How can I do read and write operations for both client and server using multithreading concept.
I'm able to write message on client side but not able to write on server side. please help me to solve this problem.
/*server function*/
int server(int argc,char *argv[])
{
int sock_fd,socknew_fd,portNo,cliLen;//socket file descriptor-sock_fd
char buff[256];
struct sockaddr_in serv_addr,cli_addr;
int n;
/*first call to socket function*/
sock_fd=socket(AF_INET,SOCK_STREAM,0); /*socket created of family type IP v4 ,socket type TCP and 0 indicates default protocol to be selected*/
if(sock_fd<0) //if -1(sock_fd) returned by socket() it shows socket cant be created
{
perror("error opening socket");
exit(0);
}
/*initialize socket structure*/
bzero((char *)&serv_addr,sizeof(serv_addr));//setting all default structure socket values to 0
portNo=atoi(argv[1]);
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=INADDR_ANY;
serv_addr.sin_port=htons(portNo);
//initialize family,server address,portno which should be of network order
/*now bind the host address using bind() call*/
if(bind(sock_fd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0)
{perror("error in binding");
exit(1);
}
/*start listening for client and be in sleep mode till any request arises from client*/
while(1)
{
listen(sock_fd,5);
cliLen=sizeof(cli_addr);
/*accept actual connection from client*/
socknew_fd=accept(sock_fd,(struct sockaddr *) &cli_addr,&cliLen);
if(socknew_fd<0)
{
perror("error in accept");
exit(1);
}
/*if connection is established start communicating*/
bzero(buff,256);
n=read(socknew_fd,buff,255);
if(buff[0]==32)
break;
if(n<0)
{perror("error in reading from socket");
exit(1);
}
printf("here is message:%s\n",buff);
/*write a response to client*/
n=write(socknew_fd,"I got your message",18);
if(n<0)
{perror("error writing in socket");
exit(1);
}
}
return 0;
}

Related

Why do tcp applications send a reset segment after close()ing the connection with data unread in the tcp receive buffer?

I've noticed that whenever I call close() from a TCP application and unread data is still inside the TCP receiving buffer the application sends a RST segment.
1)Is this the default behaviour of any TCP protocol or is OS dependent ? (I'm working on Mac Os);
2)How can I prevent the application from sending a RST segment and allow it to send a FIN even with unread data in the buffer ? Is there any way to flush this data and make the app think it has read anything?
3)Why did tcp engineers decide to implement this behaviour ?
Here is the client and server code respectively. I let the client close the connection with the '#' character still in the TCP receiving buffer on purpose :
int main(){
int sockfd;
struct sockaddr_in servaddr, cli;
//CREATE SOCKET
sockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
//Server ip and port
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr.s_addr);
servaddr.sin_port = htons(PORT_SERVER);
if (connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
if(errno == ECONNREFUSED){
printf("Host service inactive on the specified port \n");
}
else if(errno == ETIMEDOUT || errno == EHOSTUNREACH){
printf("Connection timed out ! The server could not be reached \n");
}else{
printf("Connection could not be established \n");
}
errno = 0;
close(sockfd);
return 0;
}
char buff;
while((read(sockfd,&buff,sizeof(buff))) > 0){
if(buff =='\n'){
write(1,&buff,sizeof(buff));
break;
}
write(1,&buff,sizeof(buff));
};
close(sockfd);
return 0;
}
int main(){
int sockfd, connfd;
unsigned int len;
struct sockaddr_in servaddr, cli;
//SOCKET CREATION
sockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr.s_addr);
servaddr.sin_port = htons(PORT);
if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
if ((listen(sockfd,128)) != 0) {
printf("Listen failed...\n");
exit(0);
}
for(;;){
len = sizeof(cli);
connfd = accept(sockfd,(struct sockaddr *)&cli, &len);
if (connfd < 0) {
printf("server accept failed...\n");
exit(0);
}
char hello[7]={'H','e','l','l','o','\n','#'};
write(connfd,hello,sizeof(hello));
char buffr;
int r;
while( (r=read(connfd,&buffr,sizeof(buffr))) > 0 ){}
close(connfd);
};
return 0;
}
To send a FIN use shutdown(connfd, SOCK_WR). Then, you keep reading until there is nothing left to read (read or recv returns 0), which means the other computer also sent a FIN. Then, you close the socket.
To my knowledge it is like this on all operating systems. RST is sent if another computer sends a packet to a nonexistent socket. By sending an RST when you close the socket, even if another packet wasn't received yet, your computer is being very slightly more polite by telling the other computer it's not listening any more.

TCP Socket - How to connect to server socket, then close it and connect again?

This code isn't 100% correct but I need my program to do something like this.
Client
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd==-1) exit(1);
n = connect(fd,res->ai_addr,res->ai_addrlen);
if(n==-1) exit(1);
char buffer[128] = read(fd,buffer,128);
if(strcmp(buffer,"Done\n")==0) close(fd);
n = connect(fd,res->ai_addr,res->ai_addrlen);
if(n==-1) exit(1);
bzero(buffer,128);
read(fd,buffer,128);
if(strcmp(buffer,"Done\n")==0) close(fd);
Server
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1) exit(1);
n=bind(listenfd,res2->ai_addr, res2->ai_addrlen);
if(n==-1) exit(1);
if(listen(listenfd,10) == -1) exit(1);
while(1){
User_fd = accept(listenfd,(struct sockaddr*)&addr2,&addrlen2);
if(User_fd == -1){
perror("accept");
exit(1);
}
char buffer[5] = "Done\n";
write(User_fd,buffer,5);
close(User_fd);
}
When I try to connect the second time it gives me an error "Bad file descriptor". I've tried to create a new socket on the client each time we need to connect again but it affects the other sockets I have (with different servers) and I don't think it's a good thing to do.
One cannot connect a socket twice, no matter if closed in between. One has to create a new socket instead.

Attempting to create a basic socket connection in C and running into an infinite loop on accept()

I have an assignment where I need to create a simple HTTP server to handle GET requests and return info from a directory in the directory holding the executable for this code. I am trying to establish a connection between the sockets before ironing out the HTTP requests. However, when I try to connect the client to the server using accept() it triggers an infinite loop with gdb displaying this message:
../sysdeps/unix/sysv/linux/accept.c:26
26 ../sysdeps/unix/sysv/linux/accept.c: No such file or directory.
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char* argv[]){
if(argc>1){
perror("Error there should be no command line arguments");
exit(0);
}
int sockfd = 0;
int clientfd = 0;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0){ //create socket and check for error
perror("Error in socket creation");
exit(0);
}
//create sockaddr object to hold info about the socket
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_port = 0;
server.sin_addr.s_addr = htonl(INADDR_ANY);
socklen_t sockSize = sizeof(server);
//Bind the socket to a physical address exit if there is an error
if((bind(sockfd, (struct sockaddr*)&server, sockSize))<0){
perror("Error binding socket");
exit(0);
}
//Check server details
printf("-------Server Details----------\n");
printf("Port number %d | IP ADDRESS %d\n", ntohs(server.sin_port), (getsockname(sockfd, (struct sockaddr*)&server, &sockSize)));
if((getsockname(sockfd, (struct sockaddr*)&server, &sockSize)) <0){
perror("There is an error in the sock");
exit(0);
}
if(listen(sockfd, 5) <0){
perror("Error switching socket to listen");
exit(0);
}
while((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize))){
printf("Socket is awaiting connections");
}
// figure out how to setup client to accept and submit HTTP requests
close(sockfd);
return 0;
}
accept() returns -1 on failure. An if will treat any non-zero value as a true condition.
Your loop should look more like the following:
// setup listening socket...
printf("Socket is awaiting connections");
while (1) {
sockSize = sizeof(client); // <-- add this
if ((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize)) < 0) {
if (errno != EINTR) {
// fatal error, bail out...
break;
}
continue; // retry...
}
printf("Client connected");
// use clientfd to read HTTP request and send HTTP response...
close(clientfd);
}

What is the diffrence between a concurrent tcp client server program and an iterative one?

I want to learn how to write a concurrent TCP client server in C but I can't understand the diffrence between an iterative server-client programm and a concurrent one. On the internet I could not find much information. I look over the TCP client server implementation in C from the site www.geeksforgeeks.org but I think this is an iterative example. How could I make it concurrent?
TCP Server:
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Function designed for chat between client and server.
void func(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n')
;
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
TCP Client:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
char buff[MAX];
int n;
for (;;) {
bzero(buff, sizeof(buff));
printf("Enter the string : ");
n = 0;
while ((buff[n++] = getchar()) != '\n')
;
write(sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf("From Server : %s", buff);
if ((strncmp(buff, "exit", 4)) == 0) {
printf("Client Exit...\n");
break;
}
}
}
int main()
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
As stated in the comments, an iterative server will treat each connection sequentially. In your posted example, if you run the server(after ignoring a bunch of warnings), you can only connect one client. A second client will successfully connect the server, but the server will never respond to it. Only the first client will send messages and get responses.
A concurrent implementation would treat both clients in parallel and would be able to get messages from both. I can think of 3 ways to do this, but one is not recommended:
As suggested in the comments, put the accept call in a loop. It will block until someone connects. When someone connects, you spawn a thread and give it all the information you need to communicate with the client, the file descriptor(sockfd) should suffice for a simple example. After that the thread could execute your func, for this thread will only know of one client, but the main loop will block of accept again, waiting for another connection. I found this example on google.
Using POSIX system call select(or it's alternatives poll and epoll), you can monitor a list of sockets for activity. If any of the monitored sockets has activity, a read or accept to it won`t block, and then you treat these sockets. If the server file descriptor has activity, it means a new client connected, you should store the client file descriptor somewhere, and start passing it to select as well. If a client file descriptor has activity, you handle their messages like before. This way requires no thread, everything is handled on the main routine and may have advantages depending on your use-case
I found these two examples on google: here and here
This way is not recommended: Make your server socket non-blocking with fcntl. This way, accept won't block, instead, it will immediately return signaling an error EAGAIN or EWOULDBLOCK. You can then repeatedly call accept on your main loop, most times it will return an error, but the ones that do not will signal a new client connected. When a client connects, you make its file descriptor non-blocking as well, and store it somewhere. On your main routine, for each client socket you will try a read on them, but if no new information is available, it returns an error as well. If something is available, you treat it like before. This has the disadvantage of always demanding 100% CPU utilization. You can insert a delay on the loop, but it will increase additional unnecessary latency. You should not do this.

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.

Resources