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

📄 26.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 2 页
字号:
  <br>

  <br>

4.10.  How should I choose a port number for my server? <br>

  The list of registered port assignments can be found in STD 2 or RFC <br>

  1700.  Choose one that isn't already registered, and isn't in <br>

  /etc/services on your system.  It is also a good idea to let users <br>

  customize the port number in case of conflicts with other un- <br>

  registered port numbers in other servers.  The best way of doing this <br>

  is hardcoding a service name, and using getservbyname() to lookup the <br>

  actual port number.  This method allows users to change the port your <br>

  server binds to by simply editing the /etc/services file. <br>

  <br>

4.11.  What is the difference between SO_REUSEADDR and SO_REUSEPORT? <br>

  SO_REUSEADDR allows your server to bind to an address which is in a <br>

  TIME_WAIT state.  It does not allow more than one server to bind to <br>

  the same address.  It was mentioned that use of this flag can create a <br>

  security risk because another server can bind to a the same port, by <br>

  binding to a specific address as opposed to INADDR_ANY.  The <br>

  SO_REUSEPORT flag allows multiple processes to bind to the same <br>

  address provided all of them use the SO_REUSEPORT option. <br>

  From Richard Stevens (rstevens@noao.edu): <br>

  This is a newer flag that appeared in the 4.4BSD multicasting code <br>

  (although that code was from elsewhere, so I am not sure just who <br>

  invented the new SO_REUSEPORT flag). <br>



  What this flag lets you do is rebind a port that is already in use, <br>

  but only if all users of the port specify the flag.  I believe the <br>

  intent is for multicasting apps, since if you're running the same app <br>

  on a host, all need to bind the same port.  But the flag may have <br>

  other uses.  For example the following is from a post in February: <br>

  From Stu Friedberg (stuartf@sequent.com): <br>

       SO_REUSEPORT is also useful for eliminating the <br>

       try-10-times-to-bind hack in ftpd's data connection setup <br>

       routine.  Without SO_REUSEPORT, only one ftpd thread can <br>

       bind to TCP (lhost, lport, INADDR_ANY, 0) in preparation for <br>

       connecting back to the client.  Under conditions of heavy <br>

       load, there are more threads colliding here than the <br>

       try-10-times hack can accomodate.  With SO_REUSEPORT, things <br>

       work nicely and the hack becomes unnecessary. <br>

  I have also heard that DEC OSF supports the flag.  Also note that <br>

  under 4.4BSD, if you are binding a multicast address, then <br>

  SO_REUSEADDR is condisered the same as SO_REUSEPORT (p. 731 of "TCP/IP <br>

  Illustrated, Volume 2").  I think under Solaris you just replace <br>

  SO_REUSEPORT with SO_REUSEADDR. <br>

  From a later Stevens posting, with minor editing: <br>

  Basically SO_REUSEPORT is a BSD'ism that arose when multicasting was <br>

  added, even thought it was not used in the original Steve Deering <br>



  code.  I believe some BSD-derived systems may also include it (OSF, <br>

  now Digital Unix, perhaps?).  SO_REUSEPORT lets you bind the same <br>

  address *and* port, but only if all the binders have specified it. <br>

  But when binding a multicast address (its main use), SO_REUSEADDR is <br>

  considered identical to SO_REUSEPORT (p. 731, "TCP/IP Illustrated, <br>

  Volume 2").  So for portability of multicasting applications I always <br>

  use SO_REUSEADDR. <br>

  <br>

4.12.  How can I write a multi-homed server? <br>

  The original question was actually from Shankar Ramamoorthy <br>

  (shankar@viman.com): <br>

       I want to run a server on a multi-homed host. The host is <br>

       part of two networks and has two ethernet cards. I want to <br>

       run a server on this machine, binding to a pre-determined <br>

       port number. I want clients on either subnet to be able to <br>

       send broadcast packates to the port and have the server <br>

       receive them. <br>

  And answered by Andrew Gierth (andrew@erlenstar.demon.co.uk): <br>

  Your first question in this scenario is, do you need to know which <br>

  subnet the packet came from? I'm not at all sure that this can be <br>

  reliably determined in all cases. <br>

  If you don't really care, then all you need is one socket bound to <br>



  INADDR_ANY. That simplifies things greatly. <br>

  If you do care, then you have to bind multiple sockets. You are <br>

  obviously attempting to do this in your code as posted, so I'll assume <br>

  you do. <br>

       I was hoping that something like the following would work. <br>

       Will it?  This is on Sparcs running Solaris 2.4/2.5. <br>

  I don't have access to Solaris, but I'll comment based on my <br>

  experience with other Unixes. <br>

  [Shankar's original code omitted] <br>

  What you are doing is attempting to bind all the current hosts unicast <br>

  addresses as listed in hosts/NIS/DNS. This may or may not reflect <br>

  reality, but much more importantly, neglects the broadcast addresses. <br>

  It seems to be the case in the majority of implementations that a <br>

  socket bound to a unicast address will not see incoming packets with <br>

  broadcast addresses as their destinations. <br>

  The approach I've taken is to use SIOCGIFCONF to retrieve the list of <br>

  active network interfaces, and SIOCGIFFLAGS and SIOCGIFBRDADDR to <br>

  identify broadcastable interfaces and get the broadcast addresses. <br>

  Then I bind to each unicast address, each broadcast address, and to <br>

  INADDR_ANY as well. That last is necessary to catch packets that are <br>

  on the wire with INADDR_BROADCAST in the destination.  (SO_REUSEADDR <br>

  is necessary to bind INADDR_ANY as well as the specific addresses.) <br>



  This gives me very nearly what I want. The wrinkles are: <br>

  o  I don't assume that getting a packet through a particular socket <br>

     necessarily means that it actually arrived on that interface. <br>

  o  I can't tell anything about which subnet a packet originated on if <br>

     its destination was INADDR_BROADCAST. <br>

  o  On some stacks, apparently only those with multicast support, I get <br>

     duplicate incoming messages on the INADDR_ANY socket. <br>

  <br>

4.13.  How can I read only one character at a time? <br>

  This question is usually asked by people who are testing their server <br>

  with telnet, and want it to process their keystrokes one character at <br>

  a time.  The correct technique is to use a psuedo terminal (pty). <br>

  More on that in a minute. <br>

  According to Roger Espel Llima (espel@drakkar.ens.fr), you can have <br>

  your server send a sequence of control characters: 0xff 0xfb 0x01 0xff <br>

  0xfb 0x03 0xff 0xfd 0x0f3, which translates to IAC WILL ECHO IAC WILL <br>

  SUPPRESS-GO-AHEAD IAC DO SUPPRESS-GO-AHEAD.  For more information on <br>

  what this means, check out std8, std28 and std29.  Roger also gave the <br>

  following tips: <br>

  o  This code will suppress echo, so you'll have to send the characters <br>

     the user types back to the client if you want the user to see them. <br>

  o  Carriage returns will be followed by a null character, so you'll <br>



     have to expect them. <br>

  o  If you get a 0xff, it will be followed by two more characters. <br>

     These are telnet escapes. <br>

  Use of a pty would also be the correct way to execute a child process <br>

  and pass the i/o to a socket. <br>

  I'll add pty stuff to the list of example source I'd like to add to <br>

  the faq.  If someone has some source they'd like to contribute <br>

  (without copyright) to the faq which demonstrates use of pty's, please <br>

  email me! <br>

  <br>

4.14.  I'm trying to exec() a program from my server, and attach my <br>

  socket's IO to it, but I'm not getting all the data across.  Why? <br>

  If the program you are running uses printf(), etc (streams from <br>

  stdio.h) you have to deal with two buffers.  The kernel buffers all <br>

  socket IO, and this is explained in ``section 2.11''.  The second <br>

  buffer is the one that is causing you grief.  This is the stdio <br>

  buffer, and the problem was well explained by Andrew: <br>

  (The short answer to this question is that you want to use a pty <br>

  rather than a socket; the remainder of this article is an attempt to <br>

  explain why.) <br>

  Firstly, the socket buffer controlled by setsockopt() has absolutly <br>

  nothing to do with stdio buffering. Setting it to 1 is guaranteed to <br>



  be the Wrong Thing(tm). <br>

  Perhaps the following diagram might make things a little clearer: <br>

               Process A                   Process B <br>

           +---------------------+     +---------------------+ <br>

           |                     |     |                     | <br>

           |    mainline code    |     |    mainline code    | <br>

           |         |           |     |         ^           | <br>

           |         v           |     |         |           | <br>

           |      fputc()        |     |      fgetc()        | <br>

           |         |           |     |         ^           | <br>

           |         v           |     |         |           | <br>

           |    +-----------+    |     |    +-----------+    | <br>

           |    | stdio     |    |     |    | stdio     |    | <br>

           |    | buffer    |    |     |    | buffer    |    | <br>

           |    +-----------+    |     |    +-----------+    | <br>

           |         |           |     |         ^           | <br>

           |         |           |     |         |           | <br>

           |      write()        |     |       read()        | <br>

           |         |           |     |         |           | <br>

           +-------- | ----------+     +-------- | ----------+ <br>

                     |                           |                  User space <br>

         ------------|-------------------------- | --------------------------- <br>



                     |                           |                Kernel space <br>

                     v                           | <br>

                +-----------+               +-----------+ <br>

                | socket    |               | socket    | <br>

                | buffer    |               | buffer    | <br>

                +-----------+               +-----------+ <br>

                     |                           ^ <br>

                     v                           | <br>

             (AF- and protocol-          (AF- and protocol- <br>

              dependent code)             dependent code) <br>

  Assuming these two processes are communicating with each other (I've <br>

  deliberately omitted the actual comms mechanisms, which aren't really <br>

  relevent), you can see that data written by process A to its stdio <br>

  buffer is completely inaccessible to process B. Only once the decision <br>

  is made to flush that buffer to the kernel (via write()) can the data <br>

  actually be delivered to the other process. <br>

  The only guaranteed way to affect the buffering within process A is to <br>

  change the code. However, the default buffering for stdout is <br>

  controlled by whether the underlying FD refers to a terminal or not; <br>

  generally, output to terminals is line-buffered, and output to non- <br>

  terminals (including but not limited to files, pipes, sockets, non-tty <br>

  devices, etc.) is fully buffered. So the desired effect can usually be <br>



  achieved by using a pty device; this, for example, is what the <br>

  'expect' program does. <br>

  Since the stdio buffer (and the FILE structure, and everything else <br>

  related to stdio) is user-level data, it is not preserved across an <br>

  exec() call, hence trying to use setvbuf() before the exec is <br>

  ineffective. <br>

  A couple of alternate solutions were proposed by Roger Espel Llima <br>

  (espel@drakkar.ens.fr): <br>

  If it's an option, you can use some standalone program that will just <br>

  run something inside a pty and buffer its input/output.  I've seen a <br>

  package by the name pty.tar.gz that did that; you could search around <br>

  for it with archie or AltaVista. <br>

  Another option (**warning, evil hack**) , if you're on a system that <br>

  supports this (SunOS, Solaris, Linux ELF do; I don't know about <br>

  others) is to, on your main program, putenv() the name of a shared <br>

  executable (*.so)  in LD_PRELOAD, and then in that .so redefine some <br>

  commonly used libc function that the program you're exec'ing is known <br>

  to use early.  There you can 'get control' on the running program, and <br>

  the first time you get it, do a setbuf(stdout, NULL) on the program's <br>

  behalf, and then call the original libc function with a dlopen() + <br>

  dlsym().  And you keep the dlsym() value on a static var, so you can <br>

  just call that the following times. <br>



  (Editors note:  I still haven't done an expample for how to do pty's, <br>

  but I hope I will be able to do one after I finish the non-blocking <br>

  example code.) <br>

-- <br>

※ 来源:·UNIX编程 www.tiaozhan.com/unixbbs/·[FROM: 211.69.197.132] <br>

</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="16.htm">上一层</a>][<a href="27.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>

⌨️ 快捷键说明

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