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

📄 bsd socket 简易入门手册.htm

📁 windows网络编程技术文章
💻 HTM
字号:
<html><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><title>BSD Socket 简易入门手册</title></head><body><div align="center">  <center>  <table border="0" width="750" height="243">    <tr>      <td width="673" height="243"><p align="center"><font color="#9879c6"><big><big>BSD Socket 简易入门手册</big></big></font></p><p align="right">翻译:<a href="mailto:rezaie@softhome.net">Wilbur Lang</a></p><h2>目录</h2><ul>  <li><a href="#Introduction">介绍</a>  <li><a href="#Analogy">类比 (什么是 socket ?)</a>  <li><a href="#Establish">装上你的新电话(怎样侦听?)</a>  <li><a href="#Connect">拨号 (如何调用 socket)</a>  <li><a href="#IO">谈话(如何通过 sockets 交谈)</a>  <li><a href="#Closing">挂起(结束)</a>  <li><a href="#Byte_order">世界语(交流的语言很重要)</a>  <li><a href="#Summary">未来在你的掌握了(下一步?)</a></ul><p><hr><h2><a name="Introduction">介绍</a></h2><p>当你进入 UNIX 的神秘世界后,立刻会发现越来越多的东西难以理解。对于大多数人来说,BSD socket 的概念就是其中一个。这是一个很短的教程来解释他们是什么、他们如何工作并给出一些简单的代码来解释如何使用他们。<h2><a name="Analogy">类比 (什么是 socket ?)</a></h2><p><em>socket</em> 是进行程序间通讯(IPC)的 BSD 方法。这意味着 socket 用来让一个进程和其他的进程互通信息,就象我们用电话来和其他的人交流一样。<p>用电话来比喻是很恰当的,我们在后面将一直用电话这个概念来描叙 socket 。<h2><a name="Establish">装上你的新电话(怎样侦听?)</a></h2><p>一个人要能够收到别人打给他的电话,首先他要装上一门电话。同样,你必须先建立 socket 以侦听线路。这个过程包含几个步骤。首先,你要建立一个新的 socket,就象先装上电话一样。<code>socket()</code> 命令就完成这个工作。<p>因为 sockets 有几种类型,你要注明你要建立什么类型的。你要做一个选择是 socket 的地址格式。如同电话有音频和脉冲两种形式一样,socket 有两个最重要的选项是 <strong>AF_UNIX</strong> 和 <strong>IAF_INET</strong>。<strong>AF_UNIX</strong> 就象 UNIX 路径名一样识别 sockets。这种形式对于在同一台机器上的 IPC 很有用。而 <strong>AF_INET</strong> 使用象 192.9.200.10 这样被点号隔开的四个十进制数字的地址格式。除了机器地址以外,还可以利用端口号来允许每台机器上的多个 <strong>AF_INET</strong> socket。我们这里将着重于 <strong>AF_INET</strong> 方式,因为他很有用并广泛使用。<p>另外一个你必须提供的参数是 socket 的类型。两个重要的类型是 <strong>SOCK_STREAM</strong> 和 <strong>SOCK_DGRAM</strong>。<strong>SOCK_STREAM</strong> 表明数据象字符流一样通过 socket 。而 <strong>SOCK_DGRAM</strong> 则表明数据将是数据报(<em>datagrams</em>)的形式。我们将讲解 <strong>SOCK_STREAM</strong> sockets,他很常见并易于使用。<p>在建立 socket 后,我们就要提供 socket 侦听的地址了。就象你还要个电话号码来接电话一样。<code>bind()</code> 函数来处理这件事情。<p>SOCK_STREAM sockets 让连接请求形成一个队列。如果你忙于处理一个连接,别的连接请求将一直等待到该连接处理完毕。<code>listen()</code> 函数用来设置最大不被拒绝的请求数(一般为5个)。一般最好不要使用 <code>listen()</code> 函数。<p>下面的代码说明如何利用 <code>socket()</code>、<code>bind()</code> 和 <code>listen()</code> 函数建立连接并可以接受数据。<p><listing>/* code to establish a socket; originally from bzs@bu-cs.bu.edu */int establish(unsigned short portnum){ char   myname[MAXHOSTNAME+1];  int    s;  struct sockaddr_in sa;  struct hostent *hp;  memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */  gethostname(myname, MAXHOSTNAME);           /* who are we? */  hp= gethostbyname(myname);                  /* get our address info */  if (hp == NULL)                             /* we don't exist !? */    return(-1);  sa.sin_family= hp->h_addrtype;              /* this is our host address */  sa.sin_port= htons(portnum);                /* this is our port number */  if ((s= socket(AF_INET, SOCK_STREAM, 0)) &lt; 0) /* create socket */    return(-1);  if (bind(s,&sa,sizeof(struct sockaddr_in)) &lt; 0) {    close(s);    return(-1);                               /* bind address to socket */  }  listen(s, 3);                               /* max # of queued connects */  return(s);}</listing><p> 在建立完 socket 后,你要等待对该 socket 的调用了。<code>accept()</code> 函数为此目的而来。调用 <code>accept()</code> 如同在电话铃响后提起电话一样。<code>Accept()</code> 返回一个新的连接到调用方的 socket 。<p>下面的代码演示使用是个演示。<p><listing>/* wait for a connection to occur on a socket created with establish() */int get_connection(int s){ int t;                  /* socket of connection */  if ((t = accept(s,NULL,NULL)) &lt; 0)   /* accept connection if there is one */    return(-1);  return(t);}</listing><p>和电话不同的是,在你处理先前的连接的时候,你还可以接受调用。为此,一般用 fork 来处理每个连接。下面的代码演示如何使用 <code>establish()</code> 和 <code>get_connection()</code> 来处理多个连接。<p><listing>#include &lt;errno.h&gt;       /* obligatory includes */#include &lt;signal.h&gt;#include &lt;stdio.h&gt;#include &lt;unistd.h&gt;#include &lt;sys/types.h&gt;#include &lt;sys/socket.h&gt;#include &lt;sys/wait.h&gt;#include &lt;netinet/in.h&gt;#include &lt;netdb.h&gt;#define PORTNUM 50000 /* random port number, we need something */void fireman(void);void do_something(int);main(){ int s, t;  if ((s= establish(PORTNUM)) &lt; 0) {  /* plug in the phone */    perror("establish");    exit(1);  }  signal(SIGCHLD, fireman);           /* this eliminates zombies */  for (;;) {                          /* loop for phone calls */    if ((t= get_connection(s)) &lt; 0) { /* get a connection */      if (errno == EINTR)             /* EINTR might happen on accept(), */        continue;                     /* try again */      perror("accept");               /* bad */      exit(1);    }    switch(fork()) {                  /* try to handle connection */    case -1 :                         /* bad news.  scream and die */      perror("fork");      close(s);      close(t);      exit(1);    case 0 :                          /* we're the child, do something */      close(s);      do_something(t);      exit(0);    default :                         /* we're the parent so look for */      close(t);                       /* another connection */      continue;    }  }}/* as children die we should get catch their returns or else we get * zombies, A Bad Thing.  fireman() catches falling children. */void fireman(void){  while (waitpid(-1, NULL, WNOHANG) &gt; 0)    ;}/* this is the function that plays with the socket.  it will be called * after getting a connection. */void do_something(int s){  /* do your thing with the socket here      :      :   */}</listing><h2><a name="Connect">拨号 (如何调用 socket)</a></h2><p>现在你应该知道如何建立  socket 来接受调用了。那么如何调用呢?和电话一样,你要先有个电话。用 <code>socket()</code> 函数来完成这件事情,就象建立侦听的 socket 一样。<p>在给 socket 地址后,你可以用 <code>connect()</code> 函数来连接侦听的 socket 了。下面是一段代码。<p><listing>int call_socket(char *hostname, unsigned short portnum){ struct sockaddr_in sa;  struct hostent     *hp;  int a, s;  if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the host's */    errno= ECONNREFUSED;                       /* address? */    return(-1);                                /* no */  }  memset(&sa,0,sizeof(sa));  memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */  sa.sin_family= hp->h_addrtype;  sa.sin_port= htons((u_short)portnum);  if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) &lt; 0)   /* get socket */    return(-1);  if (connect(s,&sa,sizeof sa) &lt; 0) {                  /* connect */    close(s);    return(-1);  }  return(s);}</listing><p>这个函数返回一个可以流过数据的 socket 。<h2><a name="IO">谈话(如何通过 sockets 交谈)</a></h2><p>好了,你在要传输数据的双方建立连接了,现在该传输数据了。<code>read()</code> 和 <code>write()</code> 函数来处理吧。除了在 socket 读写和文件读写中的一个区别外,和处理一般的文件一样。区别是你一般不能得到你所要的数目的数据。所以你要一直循环到你需要的数据的到来。一个简单的例子:将一定的数据读到缓存。<p><listing>int read_data(int s,     /* connected socket */              char *buf, /* pointer to the buffer */              int n      /* number of characters (bytes) we want */             ){ int bcount; /* counts bytes read */  int br;     /* bytes read this pass */  bcount= 0;  br= 0;  while (bcount &lt; n) {             /* loop until full buffer */    if ((br= read(s,buf,n-bcount)) &gt; 0) {      bcount += br;                /* increment byte counter */      buf += br;                   /* move buffer ptr for next read */    }    else if (br &lt; 0)               /* signal an error to the caller */      return(-1);  }  return(bcount);}</listing><p>相同的函数也可以写数据,留给我们的读者吧。<h2><a name="Closing">挂起(结束)</a></h2><p>和你通过电话和某人交谈后一样,你要在 socket 间关闭连接。一般 <code>close()</code> 函数用来关闭每边的 socket 连接。如果一边的已经关闭,而另外一边却在向他写数据,则返回一个错误代码。<h2><a name="Byte_order">世界语(交流的语言很重要)</a></h2><p>现在你可以在机器间联络了,可是要小心你所说的话。许多机器有自己的方言,如 ASCII 和 EBCDIC。更常见的问题是字节顺序问题。除非你一直传输的都是文本,否则你一定要注意这个问题。幸运的是,人们找出了解决的办法。<p>在很久以前,人们争论哪种顺序更“正确”。现在必要时有相应的函数来转换。其中有 <code>htons()</code>、<code>ntohs()</code>、<code>htonl()</code> 和 <code>ntohl()</code>。在传输一个整型数据前,先转换一下。<p><listing>i= htonl(i);write_data(s, &i, sizeof(i));</listing><p>在读数据后,再变回来。<p><listing>read_data(s, &i, sizeof(i));i= ntohl(i);</listing><p>如果你一直坚持这个习惯,你将比别人少出错的机会。<h2><a name="Summary">未来在你的掌握了(下一步?)</a></h2><p>就用我们刚才讨论的东西,你就可以写自己的通讯程序了。和对待所有的新生事物一样, 最好还是看看别人已经做了些什么。这里有许多关于 BSD socket 的东西可以参考。<p>请注意,例子中没有错误检查,这在“真实”的程序中是很重要的。你应该对此充分重视。<p align="center">&nbsp;</p>        <p> </td>    </tr>  </table>  </center></div></body></html>

⌨️ 快捷键说明

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