GENERAL SOCKET PROGRAMMING FAQ Last Revision: 315 PM, Jan 30, 2004 INDEX ----- Q1) I have tried to run the example programs that you provided in class (which are on your > web page) and the "Simple Stream Client". Both have failed for me. I got errors like: Undefined first referenced symbol in file socket and there seems to be a stray "\" in "Simple Stream Client." Q2) How do I print a field in hexadecimal? Q3) Your Makefile and myserver.c files have bugs that I had to fix to compile properly. And it still doesn't run properly because when I send 20 bytes of data, I get more than that. In particular, my client sends "01234567890123456789" but the server prints out: "12345678901234567890rÌôÿ¿ì@k@0n@" What is going on? Q4) Do we need any more system calls than what was in your example in the Socket Programming lecture? Q5) Why do we convert only some fields of the header and others not? To make it clear, we convert the port number but not the family (AF_INET) which is still a u_short (2 bytes). Q6) How can I avoid the non-reentrant nature of inet_ntoa() if my host doesn't have the reentrant forms? Q8) How can client and / or server tell each other which port server is listening to? Q9) When I am testing Beej's code, it seems I can only try it once. I mean, first I run the server code in one window, and use telnet or client code to get the hello information from another window, and then I use ^C to stop the server code in the first window. And then, when I tried to run the server code again, it wouldn't run, saying "bind: Address already in use". Q10) Is there any difference between read/write and send/recv? Should we use one or the other? Q11) How do I find out what ports are in use on a host? Q12) The following code printed 0.0.0.0: myAddr.sin_addr.s_addr=htonl(INADDR_ANY); ... wait for connection ... printf("myaddress: %s\n", (char *) inet_ntoa(myAddr.sin_addr)); Why? I want the IP address. Q13) After I use socket() to get the file descriptor, is there any way to get the socket related information in the reverse direction? i.e. Suppose I've already had int sd=socket() and do a connect() with sd, can I get the host ip and port number on both ends of the socket from sd? Q14) For some reason, the following code still produces 0.0.0.0: int sd, size = sizeof(struct sockaddr_in); struct sockaddr_in *myAddr; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (getsockname(sd, (struct sockaddr *)myAddr, &size) == -1) { perror("getsockname"); exit(1); } pkt->src = myAddr->sin_addr; What am I doing wrong? Q15) Why does my receiver seem to always print the last line twice? QUESTIONS/ANSWERS ----------------- Q1) I have tried to run the example programs that you provided in class last wednesday (which are on your > web page) and the "Simple Stream Client". Both have failed for me. I got errors like: Undefined first referenced symbol in file socket and there seems to be a stray "\" in "Simple Stream Client." A1) Strange. Compilers should be able to handle '\' (unless there is a character other than newline following it). Probably in getting this code off the web, your tool added an extra character after the '\'. Your undefined symbols look like it is due to missing libraries. Compile with "-lsocket -lnsl". e.g., gcc -o myserver myserver.c -lsocket -lnsl [ The Beej code is old and some .h files have changed since it was last compiled. ] HOWEVER, these library flags should only be needed on Solaris. Q2) How do I print a field in hexadecimal? A2) Here is an example: int y = 37; printf("y = %x\n", y); Q3) Your Makefile and myserver.c files have bugs that I had to fix to compile properly. And it still doesn't run properly because when I send 20 bytes of data, I get more than that. In particular, my client sends "01234567890123456789" but the server prints out: "12345678901234567890rÌôÿ¿ì@k@0n@" What is going on? A3) You are wrong. First, the code (although ancient) will compile with no changes on a Solaris host. However, if you use Linux or BSD, then you need to omit the libraries '-lsocket -lnsl' from the Makefile and you need to cast the last parameter in the call to accept(). Furthermore, you are probably getting the strange output, not because you are sending junk (although you might be), but because you have not terminated the string with the null character ('\0') before using printf() to print it. Alternatively, the client could write 21 bytes instead of 20 so as to include the null character from the client side. Q4) Do we need any more system calls than what was in your example in the Socket Programming lecture? A4) Yes. But all you should need are gettimeofday(2), getservbyport(3), htonl(3), ntohl(3), read(2), and write(2). Or instead of read and write, you could use send(2) and recv(2). Q5) Why do we convert only some fields of the header and others not? To make it clear, we convert the port number but not the family (AF_INET) which is still a u_short (2 bytes). A5) We do not convert fields that are only 1 byte long or less since they will be accessed by the software as single bytes. So there is no byte ordering issue. Byte ordering is only an issue with short, long, and floating point numbers. Note that plain text (ASCII character stream) is also not a problem. Q6) How can I avoid the non-reentrant nature of inet_ntoa() if my host doesn't have the reentrant forms? A6) Here is an example with inet_ntoa(). The calls to strncpy() copy from the static area where inet_ntoa() has left the result. struct in_addr dstaddr; char dst[INET_ADDRLEN]; ... printf ("... %15s, ... ", strncpy(dst, inet_ntoa(dstaddr), INET_ADDRSTRLEN), ...); On OSes like Solaris, you can use inet_ntop() which is reentrant. Q8) How can client and / or server tell each other which port server is listening to? A8) Our client has to know apriori what the server port number is; i.e., it is by agreement. The client port number is assigned by the system when it makes the TCP connection. It's called an "ephemeral" port number. Q9) When I am testing Beej's code, it seems I can only try it once. I mean, first I run the server code in one window, and use telnet or client code to get the hello information from another window, and then I use ^C to stop the server code in the first window. And then, when I tried to run the server code again, it wouldn't run, saying "bind: Address already in use". A9) You are causing a part of the TCP termination protocol to run. The short story is that the port you are using has to wait MSL amount of time before it becomes available again. MSL is something like 2 minutes. I suggest that after you ^C, have the server listen on a different port number. You can reuse the port though if you set the socket option SO_REUSEADDR after the socket() call but before the bind() call: conts int on = 1; if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) ... error ... Q10) Is there any difference between read/write and send/recv? Should we use one or the other? A10) For this assignment, I don't care which you use. But in short, send/recv is for sockets. read/write is I/O in general including sockets ... less flexible but also easier. Q11) How do I find out what ports are in use on a host? A11) Try netstat. On Solaris and BSD hosts, the following seems to work: netstat -a -f inet You need the -a if you want to find out what ports servers are listening upon. On Linux, try: netstat -l -A inet You can grep if you are looking for a particular port: netstat -a -f inet | grep 2000 Q12) The following code printed 0.0.0.0: myAddr.sin_addr.s_addr=htonl(INADDR_ANY); ... wait for connection ... printf("myaddress: %s\n", (char *) inet_ntoa(myAddr.sin_addr)); Why? I want the IP address. A12) Because INADDR_ANY is defined to be 0. If you want your address, either use gethostname() and convert to network number using inet_ntoa() or use getsockname(). See the man pages. Q13) After I use socket() to get the file descriptor, is there any way to get the socket related information in the reverse direction? i.e. Suppose I've already had int sd=socket() and do a connect() with sd, can I get the host ip and port number on both ends of the socket from sd? A13) Yes. getsockname() gets your address info and getpeername() gets the address info for the other end. See the man pages. Q14) For some reason, the following code still produces 0.0.0.0: int sd, size = sizeof(struct sockaddr_in); struct sockaddr_in *myAddr; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (getsockname(sd, (struct sockaddr *)myAddr, &size) == -1) { perror("getsockname"); exit(1); } pkt->src = myAddr->sin_addr; What am I doing wrong? A14) If you want to return the socket address, you have to allocate the space for it. "struct sockaddr_in *myaddr;" doesn't do it since it only allocates space for a pointer (address). Try "struct sockaddr_in myaddr;". In fact, your code probably produces corruption of your stack frame and therefore destroys who knows what other variable values. Note also that the address returned is in NBO (which is the same as HBO if on a Big Endian host like a Sun). If you print it (right after you assign to pkt->src) using something like: printf ("%x\n", pkt->src); You should see something that makes sense. For example, hilton.cec is probably 128.252.21.4 which is 0x80fc1504. I think hilton is a Sun. So, it turns out that that is also HBO. I don't know when you do your printing, so there could be another problem. Q15) Why does my receiver seem to always print the last line twice? A15) Print out the return code from xread(). You will probably discover that you did not check the return code, and you are just printing out the same buffer contents because xread() returned 0 (EOF) twice.