1

i've read here about this topic in a lot of differents ways, and i want to know whats the best practices of "creating a Linux TCP server with C and Multithreading".

so far i've read :

1-Duplicating process, with Fork().

2-Creating separated threads for each client. multithread server/client implementation in C

3-Creating Asynchronous threads for each connection

i've read that Fork and thread for each connection are not best practices, but, im not sure what really is one?

i have a small server with asynchronous threads for each connection and i have problems with bind() in the time, if i kill the process and start it again, it need like 5 minutes to start again, because i get " ERROR on binding: Address already in use " and i decided to fix it, but with the best practices.

many thanks in advance and sorry for my english .

Community
  • 1
  • 1
Luis Rubiera
  • 17
  • 1
  • 6

3 Answers3

3

Regarding your problem binding..

Set the option SO_REUSEADDR to enable binding to a port already in use (under certain circumstances). Set it before bind.

now it will work fine

...
servSock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
int optval = 1;
setsockopt(servSock,SOL_SOCKET,SO_REUSEADDR,(void *)&optval,sizeof(optval));
/* Construct local address structure */
memset(&echoServAddr,0,sizeof(echoServAddr));   /* Zero out the structure */
echoServAddr.sin_family=AF_INET;                /* Internet address family*/
echoServAddr.sin_addr.s_addr=htonl(INADDR_ANY); /* Any incoming interface */
echoServAddr.sin_port = htons(echoServPort);    /* Local port */
/* Bind to the local address */
bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr));
...
0
  1. Is obsolete since the introduction of threads.
  2. This is the most widely used technique.
  3. You've misread this. You can use asynchronous I/O, but it's a complex programming model and not to be entered into lightly.
  4. You left out non-blocking I/O with select(), poll(), epoll().

If you know what you're doing and you expect very high load you should investigate 3 or 4. Otherwise you should start with 2, as it's the easiest to program and get working, and see by observing it in production whether you have a capacity problem. Odds are than you will never need to progress beyond this model.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I'd say (2) is the easiest to get working only if by "working" you mean "runs for a few minutes/hours/days and then mysteriously deadlocks, or crashes due to an obscure race condition". For a newbie I think (1) or (4) are just as easy to program and much less likely to become a debugging nightmare. – Jeremy Friesner Oct 01 '14 at 02:31
  • @JeremyFriesner This is simply false. there are just far too many counter-examples of (2) that refute your claim that they 'mysterious[ly] deadlock' any more than anything else does. Mine have been running continuously for years. You can't seriously claim that (4) is easier to program than (2). Look at the difficulty of using `select()` for writability correctly, for a start. – user207421 Oct 29 '14 at 22:11
  • @EJP I'm willing to bet those counter-examples were not written by people who were inexperienced with multithreading. Yes, it is possible to write bug-free multithreaded code, but you have to know what you are doing and design very carefully. The newbie's logic of "It compiles, plus I ran it once (or 10 times, or 100 times) and didn't see any problems, so it must be correct" doesn't work for multithreaded programs, since they are extremely non-deterministic. – Jeremy Friesner Oct 30 '14 at 22:38
0

I would suggest you to read the doc & code of libev, that is state-of-the-art.

ciphor
  • 8,018
  • 11
  • 53
  • 70