⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 26.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               ● UNIX网络编程                       (BM: clown)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="16.htm">上一层</a>][<a href="27.htm">下一篇</a>]
<hr><p align="left"><small>发信人: fion (fion), 信区: UNP <br>

标  题: unix socket faq (5) <br>

发信站: UNIX编程 (2001年07月07日09:46:38 星期六), 站内信件 <br>

  <br>

4.  Writing Server Applications (TCP/SOCK_STREAM) <br>

  <br>

4.1.  How come I get "address already in use" from bind()? <br>

  You get this when the address is already in use.  (Oh, you figured <br>

  that much out?)  The most common reason for this is that you have <br>

  stopped your server, and then re-started it right away.  The sockets <br>

  that were used by the first incarnation of the server are still <br>

  active.  This is further explained in ``2.7 Please explain the <br>

  TIME_WAIT state.'', and ``2.5 How do I properly close a socket?''. <br>

  <br>

4.2.  Why don't my sockets close? <br>

  When you issue the close() system call, you are closing your interface <br>

  to the socket, not the socket itself.  It is up to the kernel to close <br>

  the socket.  Sometimes, for really technical reasons, the socket is <br>

  kept alive for a few minutes after you close it.  It is normal, for <br>

  example for the socket to go into a TIME_WAIT state, on the server <br>

  side, for a few minutes.  People have reported ranges from 20 seconds <br>

  to 4 minutes to me.  The official standard says that it should be 4 <br>

  minutes.  On my Linux system it is about 2 minutes.  This is explained <br>



  in great detail in ``2.7 Please explain the TIME_WAIT state.''. <br>

  <br>

4.3.  How can I make my server a daemon? <br>

  There are two approaches you can take here.  The first is to use inetd <br>

  to do all the hard work for you.  The second is to do all the hard <br>

  work yourself. <br>

  If you use inetd, you simply use stdin, stdout, or stderr for your <br>

  socket.  (These three are all created with dup() from the real socket) <br>

  You can use these as you would a socket in your code.  The inetd <br>

  process will even close the socket for you when you are done. <br>

  If you wish to write your own server, there is a detailed explanation <br>

  in "Unix Network Programming" by Richard Stevens (see ``1.5 Where can <br>

  I get source code for the book [book  title]?''). I also picked up <br>

  this posting from comp.unix.programmer, by Nikhil Nair <br>

  (nn201@cus.cam.ac.uk).  You may want to add code to ignore SIGPIPE, <br>

  because if this signal is not dealt with, it will cause your <br>

  application to exit.  (Thanks to ingo@milan2.snafu.de for pointing <br>

  this out). <br>

  I worked all this lot out from the GNU C Library Manual (on-line <br>

  documentation).  Here's some code I wrote - you can adapt it as necessary: <br>

  #include <stdio.h> <br>

  #include <stdlib.h> <br>



  #include <ctype.h> <br>

  #include <unistd.h> <br>

  #include <fcntl.h> <br>

  #include <signal.h> <br>

  #include <sys/wait.h> <br>

  /* Global variables */ <br>

  volatile sig_atomic_t keep_going = 1; /* controls program termination */ <br>

  /* Function prototypes: */ <br>

  void termination_handler (int signum); /* clean up before termination */ <br>

  int <br>

  main (void) <br>

  { <br>

    ... <br>

    if (chdir (HOME_DIR))         /* change to directory containing data <br>

                                      files */ <br>

     { <br>

       fprintf (stderr, "`%s': ", HOME_DIR); <br>

       perror (NULL); <br>

       exit (1); <br>

     } <br>

     /* Become a daemon: */ <br>

     switch (fork ()) <br>



       { <br>

       case -1:                    /* can't fork */ <br>

         perror ("fork()"); <br>

         exit (3); <br>

       case 0:                     /* child, process becomes a daemon: */ <br>

         close (STDIN_FILENO); <br>

         close (STDOUT_FILENO); <br>

         close (STDERR_FILENO); <br>

         if (setsid () == -1)      /* request a new session (job control) */ <br>

           { <br>

             exit (4); <br>

           } <br>

         break; <br>

       default:                    /* parent returns to calling process: */ <br>

         return 0; <br>

       } <br>

     /* Establish signal handler to clean up before termination: */ <br>

     if (signal (SIGTERM, termination_handler) == SIG_IGN) <br>

       signal (SIGTERM, SIG_IGN); <br>

     signal (SIGINT, SIG_IGN); <br>

     signal (SIGHUP, SIG_IGN); <br>

     /* Main program loop */ <br>



     while (keep_going) <br>

       { <br>

         ... <br>

       } <br>

     return 0; <br>

  } <br>

  void <br>

  termination_handler (int signum) <br>

  { <br>

    keep_going = 0; <br>

    signal (signum, termination_handler); <br>

  } <br>

  <br>

4.4.  How can I listen on more than one port at a time? <br>

  The best way to do this is with the select() call.  This tells the <br>

  kernel to let you know when a socket is available for use.  You can <br>

  have one process do i/o with multiple sockets with this call.  If you <br>

  want to wait for a connect on sockets 4, 6 and 10 you might execute <br>

  the following code snippet: <br>

       fd_set socklist; <br>

       FD_ZERO(&socklist); /* Always clear the structure first. */ <br>

       FD_SET(4, &socklist); <br>



       FD_SET(6, &socklist); <br>

       FD_SET(10, &socklist); <br>

       if (select(11, NULL, &socklist, NULL, NULL) < 0) <br>

         perror("select"); <br>

  The kernel will notify us as soon as a file descriptor which is less <br>

  than 11 (the first parameter to select()), and is a member of our <br>

  socklist becomes available for writing.  See the man page on select() <br>

  for more details. <br>

  <br>

4.5.  What exactly does SO_REUSEADDR do? <br>

  This socket option tells the kernel that even if this port is busy (in <br>

  the TIME_WAIT state), go ahead and reuse it anyway.  If it is busy, <br>

  but with another state, you will still get an address already in use <br>

  error.  It is useful if your server has been shut down, and then <br>

  restarted right away while sockets are still active on its port.  You <br>

  should be aware that if any unexpected data comes in, it may confuse <br>

  your server, but while this is possible, it is not likely. <br>

  It has been pointed out that "A socket is a 5 tuple (proto, local <br>

  addr, local port, remote addr, remote port).  SO_REUSEADDR just says <br>

  that you can reuse local addresses.  The 5 tuple still must be <br>

  unique!" by Michael Hunter (mphunter@qnx.com).  This is true, and this <br>

  is why it is very unlikely that unexpected data will ever be seen by <br>



  your server.  The danger is that such a 5 tuple is still floating <br>

  around on the net, and while it is bouncing around, a new connection <br>

  from the same client, on the same system, happens to get the same <br>

  remote port.  This is explained by Richard Stevens in ``2.7 Please <br>

  explain the TIME_WAIT state.''. <br>

  <br>

4.6.  What exactly does SO_LINGER do? <br>

  On some unixes this does nothing.  On others, it instructs the kernel <br>

  to abort tcp connections instead of closing them properly.  This can <br>

  be dangerous.  If you are not clear on this, see ``2.7 Please explain <br>

  the TIME_WAIT state.''. <br>

  <br>

4.7.  What exactly does SO_KEEPALIVE do? <br>

  From Andrew Gierth (andrew@erlenstar.demon.co.uk): <br>

  The SO_KEEPALIVE option causes a packet (called a 'keepalive probe') <br>

  to be sent to the remote system if a long time (by default, more than <br>

  2 hours) passes with no other data being sent or received. This packet <br>

  is designed to provoke an ACK response from the peer. This enables <br>

  detection of a peer which has become unreachable (e.g. powered off or <br>

  disconnected from the net).  See ``2.8 Why does it take so long to <br>

  detect that the peer died?''  for further discussion. <br>

  Note that the figure of 2 hours comes from RFC1122, "Requirements for <br>



  Internet Hosts". The precise value should be configurable, but I've <br>

  often found this to be difficult.  The only implementation I know of <br>

  that allows the keepalive interval to be set per-connection is SVR4.2. <br>

  <br>

4.8.  How can I bind() to a port number < 1024? <br>

  From Andrew Gierth (andrew@erlenstar.demon.co.uk): <br>

  The restriction on access to ports < 1024 is part of a (fairly weak) <br>

  security scheme particular to UNIX. The intention is that servers (for <br>

  example rlogind, rshd) can check the port number of the client, and if <br>

  it is < 1024, assume the request has been properly authorised at the <br>

  client end. <br>

  The practical upshot of this, is that binding a port number < 1024 is <br>

  reserved to processes having an effective UID == root. <br>

  This can, occasionally, itself present a security problem, e.g. when a <br>

  server process needs to bind a well-known port, but does not itself <br>

  need root access (news servers, for example). This is often solved by <br>

  creating a small program which simply binds the socket, then restores <br>

  the real userid and exec()s the real server. This program can then be <br>

  made setuid root. <br>

  <br>

4.9.  How do I get my server to find out the client's address / host- <br>

  name? <br>

  name? <br>

  From Andrew Gierth (andrew@erlenstar.demon.co.uk): <br>

  After accept()ing a connection, use getpeername() to get the address <br>

  of the client.  The client's address is of course, also returned on <br>

  the accept(), but it is essential to initialise the address-length <br>

  parameter before the accept call for this will work. <br>

  Jari Kokko (jkokko@cc.hut.fi) has offered the following code to <br>

  determine the client address: <br>

  int t; <br>

  int len; <br>

  struct sockaddr_in sin; <br>

  struct hostent *host; <br>

  len = sizeof sin; <br>

  if (getpeername(t, (struct sockaddr *) &sin, &len) < 0) <br>

          perror("getpeername"); <br>

  else { <br>

          if ((host = gethostbyaddr((char *) &sin.sin_addr, <br>

                                    sizeof sin.sin_addr, <br>

                                    AF_INET)) == NULL) <br>

              perror("gethostbyaddr"); <br>

          else printf("remote host is '%s'\n", host->h_name); <br>

  } <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -