UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

  • Index
  • » C
  • » Chat server wouldn't work

#1 2006-12-24 01:58 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Offline

#2 2006-12-24 03:43 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

You forgot to add the listen socket to the FD set...

The fd_set passed to select() will be modified, so you need to either set all fd's in the set you pass to select(), or to make a copy of the set and give that to select(). Read the manpage of select() carefully.

(Personally I think select() is an awful interface, I've always avoided it. Tastes may differ, but I prefer poll(). Best is Epoll, though that's Linux only. BSD has Kqueue, though that doesn't look that nice either at first sight, but it's more scalable and can do all kind of stuff.)

Offline

#3 2006-12-24 07:34 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Chat server> socket                     [  OK  ]
Chat server> re-use                     [  OK  ]
Chat server> bind                       [  OK  ]
Chat server> listen                     [  OK  ]
Chat server> sigaction                  [  OK  ]
Chat server> starting main loop         [  OK  ]
1
2
start reset_input
-->0<--
einde reset_input
Chat server> Connection from    [ 80.255.240.1 ]         on socket      [ 4 ]
0 ------FILEDESCRIPTOR-----> 4
Chat server> Connection lost from socket [ 4 ]   (socket hung up)
1 ------FILEDESCRIPTOR-----> 0
2 ------FILEDESCRIPTOR-----> 0
3 ------FILEDESCRIPTOR-----> 0
4 ------FILEDESCRIPTOR-----> 0
5 ------FILEDESCRIPTOR-----> 0
6 ------FILEDESCRIPTOR-----> 0
7 ------FILEDESCRIPTOR-----> 0
8 ------FILEDESCRIPTOR-----> 0
9 ------FILEDESCRIPTOR-----> 0
1
select: Bad file descriptor
pascal#

This is the output when I start a telnet session.. Why does it crash on select?

I've added the "listener" to the file descriptor set. (it was the correct one, isn't it? I used the integer generated from "socket()".)

Offline

#4 2006-12-24 08:05 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

As I said, select will modify the fd_sets you feed it, so you need to either reset all fds or give select a copy of your "us". See manpage.

Offline

#5 2006-12-24 08:46 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Hm, I'm looking on the man pages now, but.. it sais nothing about that select() modify's there fd's?
And, what do you mean with "clear the fd's"?

Offline

#6 2006-12-24 11:08 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

Offline

#7 2006-12-25 02:18 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Chat server> socket                     [  OK  ]
Chat server> re-use                     [  OK  ]
Chat server> bind                       [  OK  ]
Chat server> listen                     [  OK  ]
Chat server> sigaction                  [  OK  ]
Chat server> starting main loop         [  OK  ]
Chat server> Connection from    [ 0.0.0.0 ]      on socket      [ -1077940928 ]
0 ------FILEDESCRIPTOR-----> -1077940928

Offline

#8 2006-12-25 06:08 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

First of all, the whole point of poll() is to multiplex between multiple fds, not to literally poll each fd like you do. So if you use poll, make an array of struct pollfd with one struct for each fd you have in the set, with the first element being the listenfd. (You can also add fd once with ".events = POLLIN | POLLHUP" or other combinations, though POLLHUP is always added to .revents, and is ignored for .events). Then call poll once and search for the changed fds, checking .revents.

The ugliness of selects is mainly caused by the weird interface and the need to give a copy of fd_set. The awkward part of poll() is to manage the struct pollfd array (if you're smart you make sure there are no gaps in the array with unused elements so that searching the changed fds is faster, and you can dynamically size the array with realloc instead of having a hardcoded maximum). Notice that both force you to scan all fds to find out which one changed, which isn't very nice either (and not really scalable).

As for why your code doesn't work: Just crank up the warning level of your compiler (e.g. -Wall -W for gcc) and fix the warnings.

Offline

#9 2006-12-26 12:12 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

So, i have to use poll() in combination with select()?

Offline

#10 2006-12-26 02:02 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

No, where did I suggest that? You should call poll once each loop iteration, and let it check all sockets for events and block until something happens on any of them. Poll works the same as select, only the API is different.

The point of select and poll is that you don't have to busy loop until some data arrives, but that the program can go to sleep and get waked up when it happens.

What you did was call poll once for each socket you had. If you've blocking sockets than that destroys any performance, if you have non-blocking sockets you can as wel call send/recv directly instead of poll, and the app will hog the cpu.

Offline

#11 2006-12-27 08:04 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Hmm, How do I have to construct my main for loop for example?

I know what to do, poll() checks for every socket, not only for one etc. But I can't figure out how "create" the for loop... :(

Could anyone help me?

Offline

#12 2006-12-27 08:52 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

Ripped from years old ugly code, untested, etc. so don't use it for anything else than looking at, or bad things might happen.

for (;;){
	int n;
	short e;
	n = poll(ufds, nfds, 2000); // random 2 seconds timeout
	if (n == -1 && errno != EINTR){
		error("poll");
	} else if (n){
		uint i;
		if (ufds[0].revents){	// listen fd
			struct sockaddr_in a;
			int alen = sizeof(a);
			int fd;
			--n;
			fd = accept(ufds[0].fd, (struct sockaddr*)&a, &alen);
			if (fd == -1)
				error("accept");
			unblock(fd);
			cloexec(fd);
			if (setsockopt(fd, SOL_TCP, TCP_NODELAY, NULL, 0) == -1)
				error("nodelay");
			
			// per client init stuff
			newclient(fd);
		}
		for (i = 1; n && i <= nfds; ++i){
			e = ufds[i].revents;
			if (!e)
				continue;
			--n;
			if (e & ~(POLLIN | POLLOUT)){ // error
				delclient(i);
			}
			if (e & POLLIN){
				readfd(i);
			}
			if (e & POLLOUT){
				writefd(i);
			}
		}
	} else {
		// n==0, timeout.
	}
}

Offline

#13 2006-12-28 11:25 AM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Ok, thanx! I will look at it! :-)

How do you notice a new user or, when a user hung up in that snippet?

Offline

#14 2006-12-28 04:03 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

A new connection means that the listening fd is readable. That's what is checked first. Then all other sockets are checked for events.

For disconnecting peers I find it much easier to detect that with a zero recv(), as that should be able to handle that case already. But in this snippet if a POLLHUP happens the first check is true and delclient() is called. But better to leave that check away and do it all from recv().

Offline

#15 2006-12-28 04:52 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

when I make something with a .revents, I get this (same site for source..):

pascal# ./c
cc -O2 -fno-strict-aliasing -pipe   chat.c  -o chat
chat.c: In function `main':
chat.c:188: warning: passing arg 1 of `poll' from incompatible pointer type
chat.c:193: error: request for member `revents' in something not a structure or union
chat.c:198: error: request for member `fd' in something not a structure or union
chat.c:210: error: request for member `revents' in something not a structure or union
*** Error code 1

Stop in /socketserver.

O, erm: 'c' is a shell script I wrote, that compiles my source, and than executes it ;-)

Offline

#16 2006-12-28 07:45 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Offline

#17 2006-12-28 08:33 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

Offline

#18 2006-12-29 11:37 AM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Offline

#19 2006-12-29 02:45 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

It didn't improve much, your code... Just read what you coded, see what it does and compare that to what you want to achieve.

Change your coding style, instead of making useless minor adaptions to your broken code. And rewrite the whole thing from scratch, but now start with something that at least pretends to have some sort of design in it.

Offline

#20 2006-12-29 06:14 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Hmm, it is too difficault..

I dont know how to make a good code you know... :-(
Hmm, i mean, in this case.  Im trying for weeks, "good" code, bad code, crap code, code from a genius, code from me, but it wouldn't work...

Offline

#21 2006-12-29 07:50 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

Then try something simpler first, and practice writing increasingly more complex code. It's best to start with simple things which are easy to debug and don't depend on external things too much. Maybe buy a good C book too. After a while you'll get the hang of it and writing simple chatservers becomes peanuts. I don't know what your background is or how much experience you have, but don't expect too much too soon, it can take a while.

Offline

#22 2006-12-29 07:59 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Offline

#23 2006-12-29 08:20 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

As for how I'd might approach thing like this:

Step 1: What exactly am I going to make? What is the goal.
(Chatserver: relays data between clients)

Step 2: What are the requirements?
(Implements an existing protocol like IRC, or do you design your own? How many users, bandwidth versus latency tradeoffs, what state is stored, etc.)

Step 3: Explore solutions and building tools.
(TCP/IP, sockets, poll, select etc. If a DB is used, which one, etc. This is a bottom up step because I check if I have the required means to implement what I want. This is the moment I do research for all used tools and select which ones to use.)

Step 4: Design and choose the datastructures to use, depending on the requrements.
(In this case a "struct client" where all per client specific data is stuffed into seems logical. Depending on the chatserver protocol more may be needed. This can be seen as "objects" in OOP speak. The server itself needs a bunch of global variables to hold it's state too, like the listen fd, struct pollfd array in case of poll().)

Step 5: Design the internal API and code structure: Which functions are there, which functions call which ones and what data do they need. Repeat step 4 and 5 until something that may work pops up.
(In this case e.g. init(), mainloop(), newclient(), delclient(), handle_read(), handle_write(), parse_msg(), send_msg().)

Step 6: Actually write the code. Up until now only the structure and design was done.

Step 7: Test and debug it.
(As the code should be split up in multiple, simple chunks each part should be easy to test. If it doesn't work it's either a design fault, or something more subtle and harder to fix. In this case first get working init and mainloop functions, then test the *client functions, then the handle* functions and finally the harder *msg functions.)

Step 8: If it works, you could try adding more functionality to it. If your design is clean and modular then it should be relative easy and plainless.

It's important to first getting a functional basic framework working, and always extend on stable code, so that if something breaks you know it was a recent change that caused it. Don't change too much or stability may disappear. Keep things as simple as possible. The hard part of programming isn't to write complex code, but to write simple code that does complex things.

Offline

#24 2006-12-29 08:25 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Chat server wouldn't work

Offline

#25 2006-12-29 08:35 PM

niek
Member
Registered: 2006-12-24
Posts: 109

Re: Chat server wouldn't work

Offline

  • Index
  • » C
  • » Chat server wouldn't work

Board footer

Powered by FluxBB