<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="generator" content="pdf2htmlEX">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet" href="https://static.pudn.com/base/css/base.min.css">
<link rel="stylesheet" href="https://static.pudn.com/base/css/fancy.min.css">
<link rel="stylesheet" href="https://static.pudn.com/prod/directory_preview_static/628fc6c907732924f7821183/raw.css">
<script src="https://static.pudn.com/base/js/compatibility.min.js"></script>
<script src="https://static.pudn.com/base/js/pdf2htmlEX.min.js"></script>
<script>
try{
pdf2htmlEX.defaultViewer = new pdf2htmlEX.Viewer({});
}catch(e){}
</script>
<title></title>
</head>
<body>
<div id="sidebar" style="display: none">
<div id="outline">
</div>
</div>
<div id="pf1" class="pf w0 h0" data-page-no="1"><div class="pc pc1 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/628fc6c907732924f7821183/bg1.jpg"><div class="c x1 y1 w2 h2"><div class="t m0 x2 h3 y2 ff1 fs0 fc0 sc0 ls0 ws0">1. socket <span class="ff2">介绍<span class="_ _0"> </span></span><span class="fc1"> </span></div><div class="t m0 x3 h4 y3 ff3 fs1 fc2 sc0 ls0 ws0">所谓<span class="ff4"> socket</span>(套接字),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。</div><div class="t m0 x3 h4 y4 ff3 fs1 fc2 sc0 ls0 ws0">一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处</div><div class="t m0 x3 h4 y5 ff3 fs1 fc2 sc0 ls0 ws0">的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,</div><div class="t m0 x3 h4 y6 ff3 fs1 fc2 sc0 ls0 ws0">是应用程序与网络协议根进行交互的接口。</div><div class="t m0 x3 h4 y7 ff4 fs1 fc2 sc0 ls0 ws0">socket <span class="ff3">可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概</span></div><div class="t m0 x3 h4 y8 ff3 fs1 fc2 sc0 ls0 ws0">念。它是网络环境中进程间通信的<span class="ff4"> API</span>,也是可以被命名和寻址的通信端点,使用中的每一个套接</div><div class="t m0 x3 h4 y9 ff3 fs1 fc2 sc0 ls0 ws0">字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在</div><div class="t m0 x3 h4 ya ff3 fs1 fc2 sc0 ls0 ws0">主机的<span class="ff4"> socket </span>中,该<span class="ff4"> socket </span>通过与网络接口卡(<span class="ff4">NIC</span>)相连的传输介质将这段信息送到另外一台</div><div class="t m0 x3 h4 yb ff3 fs1 fc2 sc0 ls0 ws0">主机的<span class="ff4"> socket </span>中,使对方能够接收到这段信息。<span class="ff4">socket </span>是由<span class="ff4"> IP </span>地址和端口结合的,提供向应用</div><div class="t m0 x3 h4 yc ff3 fs1 fc2 sc0 ls0 ws0">层进程传送数据包的机制。</div><div class="t m0 x3 h4 yd ff4 fs1 fc2 sc0 ls0 ws0">socket <span class="ff3">本身有</span>“<span class="ff3">插座</span>”<span class="ff3">的意思,在</span> Linux <span class="ff3">环境下,用于表示进程间网络通信的特殊文件类型。本质为</span></div><div class="t m0 x3 h4 ye ff3 fs1 fc2 sc0 ls0 ws0">内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接</div><div class="t m0 x3 h4 yf ff3 fs1 fc2 sc0 ls0 ws0">字。与管道类似的,<span class="ff4">Linux </span>系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文</div><div class="t m0 x3 h4 y10 ff3 fs1 fc2 sc0 ls0 ws0">件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传</div><div class="t m0 x3 h4 y11 ff3 fs1 fc2 sc0 ls0 ws0">递。</div><div class="t m0 x2 h5 y12 ff4 fs1 fc0 sc0 ls0 ws0"></div><div class="t m0 x2 h3 y13 ff1 fs0 fc0 sc0 ls0 ws0">2. <span class="ff2">字节序<span class="_ _1"> </span></span><span class="fc1"> </span></div><div class="t m0 x2 h6 y14 ff2 fs2 fc0 sc0 ls0 ws0">简介<span class="_ _2"> </span><span class="ff1 fc1"> </span></div><div class="t m0 x3 h4 y15 ff3 fs1 fc2 sc0 ls0 ws0">现代<span class="ff4"> CPU </span>的累加器一次都能装载(至少)<span class="ff4">4 </span>字节(这里考虑<span class="ff4"> 32 </span>位机),即一个整数。那么这<span class="ff4"> 4 </span></div><div class="t m0 x3 h4 y16 ff3 fs1 fc2 sc0 ls0 ws0">字节在内存中排列的顺序将影响它被累加器装载成的整数的值,这就是字节序问题。在各种计算机</div><div class="t m0 x3 h4 y17 ff3 fs1 fc2 sc0 ls0 ws0">体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问</div><div class="t m0 x3 h4 y18 ff3 fs1 fc2 sc0 ls0 ws0">题,即通信双方交流的信息单元(比特、字节、字、双字等等)应该以什么样的顺序进行传送。如</div></div><div class="c x4 y19 w3 h7"><div class="t m0 x5 h8 y1a ff5 fs3 fc3 sc0 ls0 ws0">// <span class="ff6">套接字通信分两部分:</span></div><div class="t m0 x5 h8 y1b ff5 fs3 fc4 sc0 ls0 ws0">-<span class="fc0"> <span class="ff6 fc5">服务器端:被动接受连接,一般不会主动发起连接</span></span></div><div class="t m0 x5 h8 y1c ff5 fs3 fc4 sc0 ls0 ws0">-<span class="fc0"> <span class="ff6 fc5">客户端:主动向服务器发起连接</span></span></div><div class="t m0 x5 h9 y1d ff5 fs3 fc0 sc0 ls0 ws0">  </div><div class="t m0 x5 h8 y1e ff5 fs3 fc5 sc0 ls0 ws0">socket<span class="ff6">是一套通信的接口,</span>Linux<span class="fc0"> </span><span class="ff6">和</span><span class="fc0"> </span>Windows<span class="fc0"> </span><span class="ff6">都有,但是有一些细微的差别。</span></div></div><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a></div><div class="pi" data-data='{"ctm":[1.611792,0.000000,0.000000,1.611792,0.000000,0.000000]}'></div></div>
</body>
</html>
<div id="pf2" class="pf w0 h0" data-page-no="2"><div class="pc pc2 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/628fc6c907732924f7821183/bg2.jpg"><div class="c x1 y1 w2 h2"><div class="t m0 x3 h4 y1f ff3 fs1 fc2 sc0 ls0 ws0">果不达成一致的规则,通信双方将无法进行正确的编码<span class="ff7">/</span>译码从而导致通信失败。</div><div class="t m0 x3 ha y20 ff2 fs1 fc6 sc0 ls0 ws0">字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序<span class="ff8">(</span>一个字节的数</div><div class="t m0 x3 h4 y21 ff2 fs1 fc6 sc0 ls0 ws0">据当然就无需谈顺序的问题了<span class="ff8">)<span class="ff3">。</span></span></div><div class="t m0 x3 h4 y22 ff3 fs1 fc2 sc0 ls0 ws0">字节序分为大端字节序(<span class="ff7">Big-Endian</span>)<span class="ff7"> </span>和小端字节序(<span class="ff7">Little-Endian</span>)。大端字节序是指一个整</div><div class="t m0 x3 h4 y23 ff3 fs1 fc2 sc0 ls0 ws0">数的最高位字节(<span class="ff7">23 ~ 31 bit</span>)存储在内存的低地址处,低位字节(<span class="ff7">0 ~ 7 bit</span>)存储在内存的高地</div><div class="t m0 x3 h4 y24 ff3 fs1 fc2 sc0 ls0 ws0">址处;小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地</div><div class="t m0 x3 h4 y25 ff3 fs1 fc2 sc0 ls0 ws0">址处。</div><div class="t m0 x2 h6 y26 ff2 fs2 fc0 sc0 ls0 ws0">字节序举例<span class="_ _3"> </span><span class="ff8 fc1"> </span></div><div class="t m0 x6 h4 y27 ff3 fs1 fc0 sc0 ls0 ws0">小端字节序</div><div class="t m0 x6 hb y28 ff7 fs1 fc0 sc0 ls0 ws0">0x 01 02 03 04 <span class="_ _4"> </span>- ff = 255</div><div class="t m0 x6 h4 y29 ff3 fs1 fc0 sc0 ls0 ws0">内存的方向<span class="ff7"> -----></span></div><div class="t m0 x6 h4 y2a ff3 fs1 fc0 sc0 ls0 ws0">内存的低位<span class="ff7"> -----> </span>内存的高位</div><div class="t m0 x2 hb y2b ff7 fs1 fc0 sc0 ls0 ws0"> 04 03 02 01</div><div class="t m0 x2 hb y2c ff7 fs1 fc0 sc0 ls0 ws0"></div><div class="t m0 x2 hb y2d ff7 fs1 fc0 sc0 ls0 ws0"> <span class="_ _5"> </span> <span class="_ _5"> </span>0x 11 22 33 44 12 34 56 78</div><div class="t m0 x2 hb y2e ff7 fs1 fc0 sc0 ls0 ws0"></div><div class="t m0 x6 h4 y2f ff3 fs1 fc0 sc0 ls0 ws0">大端字节序</div><div class="t m0 x6 hb y30 ff7 fs1 fc0 sc0 ls0 ws0">0x 01 02 03 04 </div><div class="t m0 x6 h4 y31 ff3 fs1 fc0 sc0 ls0 ws0">内存的方向<span class="ff7"> -----></span></div><div class="t m0 x6 h4 y32 ff3 fs1 fc0 sc0 ls0 ws0">内存的低位<span class="ff7"> -----> </span>内存的高位</div><div class="t m0 x6 hb y33 ff7 fs1 fc0 sc0 ls0 ws0">01 02 03 04</div><div class="t m0 x6 hb y34 ff7 fs1 fc0 sc0 ls0 ws0">0x 12 34 56 78 11 22 33 44</div><div class="t m0 x2 hb y35 ff7 fs1 fc0 sc0 ls0 ws0"></div><div class="t m0 x2 h6 y36 ff2 fs2 fc0 sc0 ls0 ws0">字节序转换函数<span class="_ _6"> </span><span class="ff8 fc1"> </span></div><div class="t m0 x2 h4 y37 ff3 fs1 fc0 sc0 ls0 ws0">当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误的解释之。解决问题的</div><div class="t m0 x2 h4 y38 ff3 fs1 fc0 sc0 ls0 ws0">方法是:发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端知道对方传送过来的数</div><div class="t m0 x2 h4 y39 ff3 fs1 fc0 sc0 ls0 ws0">据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换(小</div><div class="t m0 x2 h4 y3a ff3 fs1 fc0 sc0 ls0 ws0">端机转换,大端机不转换)。</div></div><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a></div><div class="pi" data-data='{"ctm":[1.611792,0.000000,0.000000,1.611792,0.000000,0.000000]}'></div></div>
<div id="pf3" class="pf w0 h0" data-page-no="3"><div class="pc pc3 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/628fc6c907732924f7821183/bg3.jpg"><div class="c x1 y3b w2 h2"><div class="t m0 x7 ha y3c ff2 fs1 fc0 sc0 ls0 ws0">协议族<span class="_ _7"> </span>地址族<span class="_ _8"> </span>描述</div><div class="t m0 x7 h4 y3d ff9 fs1 fc0 sc0 ls0 ws0">PF_UNIX<span class="_ _9"> </span>AF_UNIX<span class="_ _a"> </span>UNIX<span class="ff3">本地域协议族</span></div><div class="t m0 x7 h4 y3e ff9 fs1 fc0 sc0 ls0 ws0">PF_INET<span class="_ _b"> </span>AF_INET<span class="_ _c"> </span>TCP/IPv4<span class="ff3">协议族</span></div><div class="t m0 x7 h4 y3f ff9 fs1 fc0 sc0 ls0 ws0">PF_INET6<span class="_ _d"> </span>AF_INET6<span class="_ _e"> </span>TCP/IPv6<span class="ff3">协议族</span></div><div class="t m0 x2 h4 y40 ff2 fs1 fc0 sc0 ls0 ws0">网络字节顺序<span class="ff3">是<span class="ff9"> TCP/IP </span>中规定好的一种数据表示格式,它与具体的<span class="ff9"> CPU </span>类型、操作系统等无关,从而</span></div><div class="t m0 x2 h4 y41 ff3 fs1 fc0 sc0 ls0 ws0">可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用大端排序方式。</div><div class="t m0 x2 h4 y42 ff9 fs1 fc0 sc0 ls0 ws0">BSD Socket<span class="ff3">提供了封装好的转换接口,方便程序员使用。包括从主机字节序到网络字节序的转换函数:</span></div><div class="t m0 x2 h4 y43 ff9 fs1 fc0 sc0 ls0 ws0">htons<span class="ff3">、</span>htonl<span class="ff3">;从网络字节序到主机字节序的转换函数:</span>ntohs<span class="ff3">、</span>ntohl<span class="ff3">。</span></div><div class="t m0 x2 h3 y44 ffa fs0 fc0 sc0 ls0 ws0">3. socket <span class="ff2">地址<span class="_ _0"> </span></span><span class="fc1"> </span></div><div class="t m0 x2 h6 y45 ff2 fs2 fc0 sc0 ls0 ws0">通用<span class="ffa"> socket </span>地址<span class="_ _f"> </span><span class="ffa fc1"> </span></div><div class="t m0 x2 h4 y46 ff9 fs1 fc0 sc0 ls0 ws0">socket <span class="ff3">网络编程接口中表示</span> socket <span class="ff3">地址的是结构体</span> sockaddr<span class="ff3">,其定义如下:</span></div><div class="t m0 x2 h4 y47 ff9 fs1 fc0 sc0 ls0 ws0">sa_family <span class="ff3">成员是地址族类型(</span>sa_family_t<span class="ff3">)的变量。地址族类型通常与协议族类型对应。常见的协议</span></div><div class="t m0 x2 h4 y48 ff3 fs1 fc0 sc0 ls0 ws0">族(<span class="ff9">protocol family</span>,也称<span class="ff9"> domain</span>)和对应的地址族入下所示:</div><div class="t m0 x2 h4 y49 ff3 fs1 fc0 sc0 ls0 ws0">宏<span class="ff9"> PF_* </span>和<span class="ff9"> AF_* </span>都定义在<span class="ff9"> bits/socket.h </span>头文件中,且后者与前者有完全相同的值,所以二者通常混</div><div class="t m0 x2 h4 y4a ff3 fs1 fc0 sc0 ls0 ws0">用。</div></div><div class="c x4 y4b w3 h7"><div class="t m0 x5 h8 y4c ff5 fs3 fc5 sc0 ls0 ws0">h<span class="fc0"> <span class="fc4">-</span> </span>host<span class="fc0"> </span><span class="ff6">主机,主机字节序</span></div><div class="t m0 x5 h8 y4d ff5 fs3 fc5 sc0 ls0 ws0">to<span class="fc0"> <span class="fc4">-</span> </span><span class="ff6">转换成什么</span></div><div class="t m0 x5 h8 y4e ff5 fs3 fc5 sc0 ls0 ws0">n<span class="fc0"> <span class="fc4">-</span> </span>network<span class="fc0"> </span><span class="ff6">网络字节序</span></div><div class="t m0 x5 h9 y4f ff5 fs3 fc5 sc0 ls0 ws0">s<span class="fc0"> <span class="fc4">-</span> <span class="fc7">short</span> <span class="fc7">unsigned</span> <span class="fc7">short</span></span></div><div class="t m0 x5 h9 y50 ff5 fs3 fc5 sc0 ls0 ws0">l<span class="fc0">  <span class="fc4">-</span> <span class="fc7">long</span>  <span class="fc7">unsigned</span> <span class="fc7">int</span></span></div></div><div class="c x4 y51 w3 hc"><div class="t m0 x5 h9 y52 ff5 fs3 fc8 sc0 ls0 ws0">#include <arpa/inet.h></div><div class="t m0 x5 h8 y53 ff5 fs3 fc3 sc0 ls0 ws0">// <span class="ff6">转换端口</span></div><div class="t m0 x5 h8 y54 ff5 fs3 fc7 sc0 ls0 ws0">uint16_t<span class="fc0"> <span class="fc9">htons</span>(</span>uint16_t<span class="fc0"> <span class="fc5">hostshort</span>); <span class="fc3">// <span class="ff6">主机字节序</span> - <span class="ff6">网络字节序</span></span></span></div><div class="t m0 x5 h8 y55 ff5 fs3 fc7 sc0 ls0 ws0">uint16_t<span class="fc0"> <span class="fc9">ntohs</span>(</span>uint16_t<span class="fc0"> <span class="fc5">netshort</span>); <span class="fc3">// <span class="ff6">主机字节序</span> - <span class="ff6">网络字节序</span></span></span></div><div class="t m0 x5 h8 y56 ff5 fs3 fc3 sc0 ls0 ws0">// <span class="ff6">转</span>IP</div><div class="t m0 x5 h8 y57 ff5 fs3 fc7 sc0 ls0 ws0">uint32_t<span class="fc0"> <span class="fc9">htonl</span>(</span>uint32_t<span class="fc0"> <span class="fc5">hostlong</span>); <span class="fc3">// <span class="ff6">主机字节序</span> - <span class="ff6">网络字节序</span></span></span></div><div class="t m0 x5 h8 y58 ff5 fs3 fc7 sc0 ls0 ws0">uint32_t<span class="fc0"> <span class="fc9">ntohl</span>(</span>uint32_t<span class="fc0"> <span class="fc5">netlong</span>); <span class="fc3">// <span class="ff6">主机字节序</span> - <span class="ff6">网络字节序</span></span></span></div></div><div class="c x4 y59 w3 hd"><div class="t m0 x5 h8 y5a ff5 fs3 fc3 sc0 ls0 ws0">// socket<span class="ff6">地址其实是一个结构体,封装端口号和</span>IP<span class="ff6">等信息。后面的</span>socket<span class="ff6">相关的</span>api<span class="ff6">中需要使用到这个</span></div><div class="t m0 x5 h8 y5b ff5 fs3 fc3 sc0 ls0 ws0">socket<span class="ff6">地址。</span></div><div class="t m0 x5 h8 y5c ff5 fs3 fc3 sc0 ls0 ws0">// <span class="ff6">客户端</span> -> <span class="ff6">服务器(</span>IP, Port<span class="ff6">)</span></div></div><div class="c x4 y5d w3 he"><div class="t m0 x5 h9 y5e ff5 fs3 fc8 sc0 ls0 ws0">#include <bits/socket.h></div><div class="t m0 x5 h9 y5f ff5 fs3 fca sc0 ls0 ws0">struct<span class="fc0"> <span class="fc9">sockaddr</span> {</span></div><div class="t m0 x5 h9 y60 ff5 fs3 fc0 sc0 ls0 ws0"> <span class="fc5">sa_family_t</span> <span class="fc5">sa_family</span>;</div><div class="t m0 x5 h9 y61 ff5 fs3 fc0 sc0 ls0 ws0"> <span class="fc7">char</span>    <span class="fc5">sa_data</span>[<span class="fcb">14</span>];</div><div class="t m0 x5 h9 y62 ff5 fs3 fc0 sc0 ls0 ws0">};</div><div class="t m0 x5 h9 y63 ff5 fs3 fca sc0 ls0 ws0">typedef<span class="fc0"> <span class="fc7">unsigned</span> <span class="fc7">short</span> <span class="fc7">int</span> <span class="fc5">sa_family_t</span>;</span></div></div><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a><a class="l" rel='nofollow' onclick='return false;'><div class="d m1"></div></a></div><div class="pi" data-data='{"ctm":[1.611792,0.000000,0.000000,1.611792,0.000000,0.000000]}'></div></div>