Friday, June 25, 2010

TCP/IP programming socket port doubts

In a simple client server code for TCP/IP: 
server side : 
int sock2 = accept(sock1,&client,&clength);

client side : 
int sock1 = socket(AF_INET,SOCK_STREAM,0);
value of sock1 at client side is 3,
and value of sock2 at server side is 4.
but ain't both the sockets same?
then what do these values denote?
Secondly, on the server side I can print
the port number of the client by cli.sin_port.
From where does that port number come?
Who assigns that port number to the client?
Client machine itself? When does that assignment happen?
I compiled my code like gcc -g filename, but could
not step into the functions like accept,connect,bind etc.\
with gdb.
What do I need to do in order to step inside these function
Do I really need to typecast variables of type "struct sockaddr_in"
to "struct sockaddr"? Since my code compiles simply with a warning
and runs fine, if I don't do this typecasting.
If I include only <arpa/inet.h> and no other header files,like <sys/socket.h>,
then my code doesn't even give a warning, if I don't do this typecasting. 
In fact, if I pass
"serv" in place of "&serv", even then there is no error/warning while
compiling. But the code doesn't work. Why?

Ans : 
A socket has 2 endpoints. Each endpoint has a unique IP address / port combination. So your two socket file units open different entities.
connect(), accept() et al are implemented by operating system. You cannot step into the operating system with userland gdb. You can debug the operating system with its own tools (I have not yet done this - the most I have done is to insert printk calls).
I hope that's a start towards answering your questions - post what you next want to know.

"can't the communication happen between client
and server since they know each other's IP and port

It does happen. It happens over the socket. User applications often don't  concern themselves with both port numbers. A client knows which port / IP it needs to call, it may not car which local port was involved (or even what is the local IP address). The operating system needs this information, so it may interpret and construct IP and TCP headers of the network frames.

Ans  :
The operating system does an implicit bind() of a connecting socket which does not have a local "name" (address / port pair). You could program that bind() yourself before calling connect(), either with a nonzero socket number (which must not be in use to the address (interface) to which you are binding) or leave the port zero and the system will choose an unused one. It is not a good idea to do this, because you bind the socket to a particular IP address (i.e. a particular Network Interface), unless you first consult the routing tables to find out which is the correct interface to which to bind. The operating system will do all that for you.

If you don't typecast to "struct sockaddr", uou can potentially get a warning that you are supplying an incompatible pointer type as an argument. Not all sockets have a port you see (e.g. SOCK_RAW sockets don't), so function prototypes specify the functions take "struct sockaddr" although for regular tcp/ip programming you will be supplying a "struct sockaddr_in". Yes the code will compile with a warning and run just fine - but the value of warnings in general is lost unless you are always aiming for a warning-free compile.

In the absence of a function prototype (as a header file might supply), the C compiler is unable to verify, promote or convert any arguments on the fly - you have to always supply exactly correct argument types and you will get no warning if you don't. Worse still, some "functions" may actually be macros and you will miss out on the macro expansion. This is the case with stat() for instance. To see whether  this applies to your code, do something like:

gcc -E -C myprog.c -o myprog.S

to only pre-process the code. Now take out the header files you took out before, and do:

gcc -E -C myprog.c -o myprog_bad.S

Your code will be the last few lines of each .S file. You should be able to find it easily because -C preserves comments (you do use comments, don't you?). Inspect your code for differences with and without the required headers. 
You  could also make a habit of compiling -Wall -Wmissing-prototypes -Wstrict-prototypes. Then you certainly would get warnings when omitting required headers. I always compile that way.

No comments:

Blog Archive