LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-21-2020, 03:02 PM   #1
intstudent123
LQ Newbie
 
Registered: Jan 2020
Location: Japan
Posts: 4

Rep: Reputation: Disabled
Question Why does my server cannot respond to multiple clients simultaneously even after using fork function?


Hi, I'm a newbie here. I'm trying to create an SMTP server that can respond to multiple clients simultaneously. I use the fork function in socket programming. Below is the server program (not including the variables).

smtp.c

Code:
  ...
	system("clear");
	// create socket
	if((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERR){
		perror("socket: ");
		exit(-1);
	}

	server.sin_family = AF_INET;
	server.sin_port = htons(SMTP);
	server.sin_addr.s_addr = INADDR_ANY;

	// bind
	len = sizeof(struct sockaddr_in);
	if(bind(sock, (struct sockaddr *)&server, sizeof(server)) == ERR){
		perror("bind");
		exit(-1);
	}

	// listen
	if((listen(sock, 10)) == ERR){
		perror("listen");
		exit(-1);
	}

	while(1){
		memset(buff, 0, sizeof(buff));
		memset(msg, 0, sizeof(msg));
		memset(to, 0, sizeof(to));
		memset(Cc, 0, sizeof(Cc));

		printf("(SMTP) Waiting for connection\n");
		if((cli = accept(sock, (struct sockaddr *)&client, &len)) == ERR){
			perror("accept");
			exit(-1);
		}

		// create child process
		child_pid = fork();

		if (child_pid < 0) {	
			perror("fork");
			exit(-1);
		}
		// child
		else if (child_pid == 0) {
			close(sock);		// close child copy
			// receive from client
			recv(cli, to, sizeof(msg), 0);
			printf("Connection request to %s\n",to);

			for(k=0;;k++){
				sprintf(file_dir,"%s/mail%d.txt", to, k+1);
				if ((fp = fopen(file_dir, "r")) == NULL) break;
			}
	    			fp = fopen(file_dir, "w");
				while(strcmp(msg,".") != 0){
					recv(cli, msg, sizeof(msg),0);
					if(strcmp(msg,".") == 0){
						strcpy(buff, "1");
					}
					else{
						strcpy(buff, "0");
					}
				fprintf(fp, "%s\n", msg);
				send(cli, buff, sizeof(buff), 0);
				}

			fclose(fp);
			// Cc
			// init buff and msg
			memset(buff, 0, sizeof(buff));
			memset(msg, 0, sizeof(msg));
			// process
			recv(cli, Cc, sizeof(msg), 0);
			printf("Connection request to %s\n\n",Cc);
	
			for(k=0;;k++){
				sprintf(file_dir,"%s/mail%d.txt", Cc, k+1);
				if ((fp = fopen(file_dir, "r")) == NULL) break;
			}
				fp = fopen(file_dir, "w");
				while(strcmp(msg,".") != 0){
					recv(cli, msg, sizeof(msg),0);
					if(strcmp(msg,".") == 0){
						strcpy(buff, "1");
					}
					else{
						strcpy(buff, "0");
					}
					fprintf(fp, "%s\n", msg);
					send(cli, buff, sizeof(buff), 0);
				}

			fclose(fp);
			close(cli);
			exit(0);		// child exits here
		}
		// parent
		else{
			close(cli);		// close parent copy
			waitpid(child_pid, NULL, 0);	// waits for child to exit
		}
	}
	close(sock);
	return 0;
        ...
To test it, I open two terminals, for example, A and B. At A's terminal, I write emails to C and B. At the same time, I write emails at B's terminal to A and C. After entering '.' at A's terminal to send the emails, I tried to send B's emails without exiting from A's terminal.

The result turns out like this:

Quote:
(SMTP)Waiting for connection
Connection request to C
Connection request to B

(SMTP)Waiting for connection
Connection request to
(SMTP)Waiting for connection
But I want the result to be like this:

Quote:
(SMTP) Waiting for connection
Connection request to C
Connection request to B

(SMTP) Waiting for connection
Connection request to A
Connection request to C

(SMTP) Waiting for connection
Are there any mistakes in the flow of the coding? It would be great if there's anyone that can help so that I can improve my understanding of socket and fork. Thank you in advance.

Last edited by intstudent123; 01-21-2020 at 05:11 PM. Reason: Details
 
Old 01-21-2020, 04:21 PM   #2
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,266
Blog Entries: 24

Rep: Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195
Hi, and welcome to LQ!

Although the rules here ask that you not post homework or school assignments verbatim, members are happy to help if you are having difficulty with specific problems.

Posting whole code and asking others to debug it for you is not a good way to get help. Everyone volunteers their time, so working up a simplest example which reproduces the problem for others is always appreciated! And it is the best learning exercise for you as well - very often in the process of explaining the problem to others in simplest terms you will understand it well enough to fix it yourself!

What have you done to troubleshoot the problem? Are any error messages produced when the connection fails, and if so, what are they?

Please review the Site FAQ for guidance in posting your questions and general forum usage. Especially, read the link in that page, How To Ask Questions The Smart Way. The more effort you put into understanding your problem and framing your questions, the better others can help!
 
1 members found this post helpful.
Old 01-21-2020, 07:59 PM   #3
Geist
Member
 
Registered: Jul 2013
Distribution: Slackware 14 / current
Posts: 442

Rep: Reputation: 196Reputation: 196
Why not wrap some of that code into functions so you don't have one huge main one?
The benefit of it that if a smaller function works as intended, it's less noise, less to think about vs it being expanded.

This also helps with debugging, especially variable scope problems since it's easy to overlook one of the many variables required for a huge spaghetti function.
That is because inside the then encapsulated function, the variable it needs must be there and set correctly, which is easier to manage if the scope of the variable is, well, constrained to only the function.

So if you had a variable like "sock", and it were worked with in 10 places in the code, then it would be easy for that to mess up in one huge spaghetti function, vs 1 or 2 times per small function, which you feed the sock variable as an argument, and have it returned.

Code:
int rock(int sock)
{
   return sock + 5;
}

int rockem_sockem(int sock){
return rock(sock);
}

int mockem_mockem(int sock){
return sock + 10;
}

int trocken_bocken(int sock){
return sock + 20;
}

int main(){
int sock = 0;
sock = rockem_sockem(sock);
sock = mockem_mockem(sock);
sock = trocken_bocken(sock);
//etc
return 0;
}
Now you have several encased places where working with sock might fail instead of sock being strewn all over the place like actual socks, having 10 different loops, functions and whatnots all meddle with it in one big place.

Last edited by Geist; 01-21-2020 at 08:01 PM.
 
Old 01-22-2020, 06:50 AM   #4
GazL
LQ Veteran
 
Registered: May 2008
Posts: 6,897

Rep: Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019
Quote:
Originally Posted by intstudent123 View Post
Are there any mistakes in the flow of the coding? It would be great if there's anyone that can help so that I can improve my understanding of socket and fork. Thank you in advance.
Unless I'm reading it wrong, you have a waitpid(child_pid,...) call within your accept() main loop. That's going to serialise client processing. Your server won't accept() a new client until the last one has been processed fully, effectively negating the purpose of forking the client processing to the background.

You need to remove that waitpid from the main loop, and handle child reaping with a SIGCHLD signal handler.


Beej's excellent guide may be of interest to you: http://beej.us/guide/bgnet/html/

Last edited by GazL; 01-22-2020 at 06:56 AM.
 
3 members found this post helpful.
Old 01-22-2020, 03:26 PM   #5
intstudent123
LQ Newbie
 
Registered: Jan 2020
Location: Japan
Posts: 4

Original Poster
Rep: Reputation: Disabled
Thank you for the advice! I tried to use SIGCHLD, but it did not work. Maybe there's something wrong at the client program. I'll just do my best.
 
1 members found this post helpful.
Old 01-22-2020, 07:07 PM   #6
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,866
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Then periodically try some non-blocking version of wait:
Code:
pid_t exitedchild= waitpid(-1, &wstatus, WNOHANG);

Last edited by NevemTeve; 01-22-2020 at 07:21 PM.
 
Old 01-23-2020, 02:04 AM   #7
intstudent123
LQ Newbie
 
Registered: Jan 2020
Location: Japan
Posts: 4

Original Poster
Rep: Reputation: Disabled
I understand that the flow of the socket programming and fork function is correct, but where should I put the
Code:
pid_t exitedchild= waitpid(-1, &wstatus, WNOHANG);
? Should I put in the main loop during declaration of the variables?
 
Old 01-23-2020, 02:12 AM   #8
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,866
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
An option is calling it right after (or before) 'accept'.
 
1 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Why does my server cannot respond to multiple clients simultaneously even after using fork function? intstudent123 Linux - Newbie 3 01-21-2020 07:45 PM
[SOLVED] "Unable to fork: Cannot allocate memory" even 10GB RAM free postcd Linux - General 10 06-05-2016 12:03 PM
[SOLVED] Server can ping clients, but clients cannot ping server and i cannot SSH into Server jzakharia Linux - Networking 5 07-05-2015 02:21 PM
[SOLVED] Threaded function cannot call a function with extern "C" but nonthreaded function can morty346 Programming 16 01-12-2010 05:00 PM
Multiple Blade servers booting from multiple disk drives simultaneously NGC_cheryl Linux - Enterprise 0 11-26-2007 08:38 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:30 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration