﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-再别流年的技术实验室-随笔分类-socket 编程入门教程</title><link>http://www.cppblog.com/lf426/category/7534.html</link><description>Game Design Using C++ and SDL</description><language>zh-cn</language><lastBuildDate>Sun, 13 Jun 2010 01:45:38 GMT</lastBuildDate><pubDate>Sun, 13 Jun 2010 01:45:38 GMT</pubDate><ttl>60</ttl><item><title>socket 编程入门教程（六）UDP应用：2、UDP版的Echo Client</title><link>http://www.cppblog.com/lf426/archive/2010/06/12/117690.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 12 Jun 2010 04:11:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/12/117690.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117690.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/12/117690.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117690.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117690.html</trackback:ping><description><![CDATA[<p>同样的，我们将UDP版的doEcho()也设计成返回bool：true表示循环继续；false表示关闭客户端。</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;UDPEchoClient:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;UDPClientSock{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;UDPEchoClient(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPEchoClient();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;doEcho(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;echo_message);<br>};</span></div>
我们依然使用C++字符串。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">UDPEchoClient::UDPEchoClient(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>UDPClientSock(pre_buffer_size)<br>{}<br><br>UDPEchoClient::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPEchoClient()<br>{}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;UDPEchoClient::doEcho(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;echo_message)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;UDPSendtoDest(echo_message.data(),&nbsp;echo_message.size())&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(echo_message&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/shutdown</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(UDPReceive()&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout.write(preBuffer,&nbsp;preReceivedLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>}</span></div>
当echo_message为&#8220;空&#8221;的时候，即输入直接回车，是一个""，用C风格来说，即时'\0'，从C++来说，是const char[1]，其C++风格的长度echo_message.size()为0，这时候就会发送一个&#8220;0长度&#8221;的UDP数据包。<br>另外，我们小心设计了关闭服务器的请求，发送/shutdown后，客户端会自动返回false，表示会关闭，不再等待来自服务器的recvfrom()。否则，服务器已经关闭，recvfrom()则会一直阻塞。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">])&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;WinsockAPI&nbsp;winsockInfo;<br>&nbsp;&nbsp;&nbsp;&nbsp;winsockInfo.showVersion();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;UDPEchoClient&nbsp;echo_client;<br>&nbsp;&nbsp;&nbsp;&nbsp;echo_client.UDPSetDest(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">],&nbsp;server_port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(msg&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/exit</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;go_on){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Echo:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::getline(std::cin,&nbsp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_client.doEcho(msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
主程序中，如果使用/exit，会先发送给服务器，然后再关闭。<br>本章完整源代码：<br>Linux：<br><a href="http://www.163pan.com/files/c0l000h0t.html">http://www.163pan.com/files/c0l000h0t.html</a><br>win32：<br><a href="http://www.163pan.com/files/c0o000h09.html">http://www.163pan.com/files/c0o000h09.html</a>
<img src ="http://www.cppblog.com/lf426/aggbug/117690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-12 12:11 <a href="http://www.cppblog.com/lf426/archive/2010/06/12/117690.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（六）UDP应用：1、UDP版的Echo Server</title><link>http://www.cppblog.com/lf426/archive/2010/06/12/117689.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 12 Jun 2010 03:16:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/12/117689.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117689.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/12/117689.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117689.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117689.html</trackback:ping><description><![CDATA[与TCP版的Echo Server类似，我们从Server Socket类中派生出Echo Server类。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;UDPEchoServer:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;UDPServerSock{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;UDPEchoServer(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPEchoServer();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;handEcho();<br>};</span></div>
我们依然让handEcho()返回一个bool，true表示客户端&#8220;正常&#8221;离开（这里没用&#8220;断开&#8221;这个词是因为UDP是无连接的；另外，我们这里用recvfrom()返回小于0来表示客户端其实是&#8220;非正常&#8221;的离开了，比如连接被重置。事实上，作为UDP服务器，根本不关心客户端是在连还是已经离开），false表示客户端发出指令要求服务器端关闭。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">UDPEchoServer::UDPEchoServer(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>UDPServerSock(server_port,&nbsp;pre_buffer_size)<br>{}<br><br>UDPEchoServer::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPEchoServer()<br>{}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;UDPEchoServer::handEcho()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/shutdown</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(UDPReceive()&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;cmd(preBuffer,&nbsp;SHUTDOWN_CMD.size());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(cmd&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">&amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;<span style="COLOR: #0000ff">static_cast</span>&lt;<span style="COLOR: #0000ff">int</span>&gt;(</span><span style="COLOR: #000000">SHUTDOWN_CMD.size()))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client&nbsp;(&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;inet_ntoa(lastfromSockAddr.sin_addr)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;ntohs(lastfromSockAddr.sin_port)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;)&nbsp;sent&nbsp;a&nbsp;message.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UDPSetDest(lastfromSockAddr);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UDPSendtoDest(preBuffer,&nbsp;preReceivedLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>}</span></div>
这里跟TCP有些细微的差别。在TCP中，recv()返回0表示连接正常断开，而UDP中没有连接和断开的概念，recv()或者recvfrom()返回0表示收到一个0字节大小数据的数据报。另外，因为TCP是一对一连接的，所以一旦连接上，TCP服务器只能处理来自一个客户端的echo请求（后面会讲到多线程的使用，就可以让TCP同时处理多个客户端了）；而UDP服务器则可以处理来自任何客户端的echo请求，为了返回信息到正确的客户端，我们的策略是，接收一个UDP数据包后，马上刷新发送目标地址为上一次接收地址，然后再回发数据，所以这里每次多了一个重新指定发送目的地的函数。<br>最后，主程序基本不需要改变：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">])&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;UDPEchoServer&nbsp;echo_server(server_port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(go_on){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_server.handEcho();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
本章完整源代码下载：<br>Linux：<br><a href="http://www.163pan.com/files/c0l000h0s.html">http://www.163pan.com/files/c0l000h0s.html</a><br>win32：<br><a href="http://www.163pan.com/files/c0o000h08.html">http://www.163pan.com/files/c0o000h08.html</a> 
<img src ="http://www.cppblog.com/lf426/aggbug/117689.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-12 11:16 <a href="http://www.cppblog.com/lf426/archive/2010/06/12/117689.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（五）UDP原理：5、预读MSG_PEEK</title><link>http://www.cppblog.com/lf426/archive/2010/06/11/117631.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Fri, 11 Jun 2010 05:30:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/11/117631.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117631.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/11/117631.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117631.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117631.html</trackback:ping><description><![CDATA[recv()和recvfrom()的第4个参数可以调整函数行为。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">types.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>ssize_t&nbsp;recv(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;s,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">buf,&nbsp;size_t&nbsp;len,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;flags);<br>ssize_t&nbsp;recvfrom(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;s,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">buf,&nbsp;size_t&nbsp;len,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;flags,<br></span><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct</span><span style="COLOR: #000000">&nbsp;sockaddr&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">from,&nbsp;socklen_t&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">fromlen);</span></div>
因为UDP是按数据包接收的，我们在接收之前并不知道这个数据包有多大。一个策略是，我们准备足够大的应用程序缓存以免出错，但是这个&#8220;足够大&#8221;的概念是建立在我们对传送的数据事先有了解的情况下，比如是我们自己设计服务器端和客户端并且制定应用层协议；另外一种策略是，将一个数据包的相关信息记录在数据包的前面的一些字节中，比如说大小，这样，我们可以通过预读数据包的前面一段，得到这个数据包的相关信息，比如说大小，然后再安排缓存。<br>这个预读的flag就是MSG_PEEK。使用预读后，RecvQ的下一条UDP数据包信息被读出来，但是并不从RecvQ中弹出。<br>UDP也可以通过recvfrom()预读获得来向的远程地址，从而可以提供给比如connect()等函数使用。<br>需要说明的是，在Linux下（我是Debian系统）从一个n字节的UDP数据包中预读取小于n个字节的数据是完全没有问题的；但是在WinSock下会引起一个异常10040（WSAEMSGSIZE），即是说win32下recv()或者recvfrom()在这种情况下会返回-1。其异常信息大概是读取的数据长度小于数据包的长度——而这个正是我们计划中的事情。
<img src ="http://www.cppblog.com/lf426/aggbug/117631.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-11 13:30 <a href="http://www.cppblog.com/lf426/archive/2010/06/11/117631.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（五）UDP原理：4、“有连接”的UDP</title><link>http://www.cppblog.com/lf426/archive/2010/06/11/117629.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Fri, 11 Jun 2010 03:51:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/11/117629.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117629.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/11/117629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117629.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117629.html</trackback:ping><description><![CDATA[<p>虽然UDP是无连接的，但是也可以通过调用connect()将本地的UDP socket FD与一个远程的UDP socket FD连接起来——只需要指定这个远程sockFD的地址，假设这个地址是sockaddr_in remoteSockAddr，代码如下：</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(connect(sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">remoteSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(remoteSockAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">connect()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
建立连接后的UDP RecvQ就不会将非来自remoteSockAddr的数据包收入。<br>请注意UDP的connect()与TCP的connect()很不相同，TCP是连接服务器的监听socket，并且会阻塞直到服务器调用accept()。一般的说法，UDP的连接并不会改变UDP的各种特点，比如，即使连接，UDP也不知道远程主机是否在线连接或者是否断开——但是，我个人认为，改变了本机的RecvQ接收数据包的过滤机制，也就改变了UDP原本可以接收来自任何地址信息的属性。<br>如果希望断开UDP的连接，需要使用一个特定的&#8220;断开&#8221;地址，代码如下：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;sockaddr&nbsp;descon_sock_addr;<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">descon_sock_addr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(descon_sock_addr));<br>&nbsp;&nbsp;&nbsp;&nbsp;descon_sock_addr.sa_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_UNSPEC;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(connect(sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">descon_sock_addr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(descon_sock_addr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">des&nbsp;connect()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
请注意这里的地址族AF_UNSPEC直接赋值给了一个sockaddr结构。我试过，使用sockaddr_in也是可以的，但是无论是哪个结构，首先都得将整个结构对象清零，否则可能报错。
<img src ="http://www.cppblog.com/lf426/aggbug/117629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-11 11:51 <a href="http://www.cppblog.com/lf426/archive/2010/06/11/117629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（五）UDP原理：3、UDP的系统缓存队列</title><link>http://www.cppblog.com/lf426/archive/2010/06/11/117628.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Fri, 11 Jun 2010 03:18:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/11/117628.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117628.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/11/117628.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117628.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117628.html</trackback:ping><description><![CDATA[UDP的系统缓存队列与TCP的相比，有两点显著的不同：<br>1、UDP没有SendQ。UDP的数据包不会被处理，通过调用sendto()（或者在connect()之后也可以调用send()）将数据直接发送。<br>2、UDP的数据在缓存队列中是有边缘保证的，也就是说，数据包是有大小的。每次调用recvfrom()（或者在connect()之后调用recv()）都会试图接收一个完整的数据包——因此，UDP程序所指定的接收缓存大小应该足够存放每一个UDP数据包，否则，多余的部分就会被抛弃，并且recvfrom()（或recv()）返回一个异常（-1，并且抛出异常代码）。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p07.jpg" width=646 height=320><br>（在上图中，我们用虚线的数据包边缘表示TCP中的无边缘保证；而UDP中字节之间用虚线隔开表示UDP的数据不会以字节为单位进行传输）<br>此外，UDP的RecvQ还可能存在于TCP的第三个不同：我们说，UCP是无连接的，当然，我们也可以调用connect()将UDP连接起来，但是在默认无连接的情况下，UDP的RecvQ中可以缓存来自所有远程地址的数据包——这不仅仅在很多时候很不方便，如果我们只希望接收一个特定地址的数据，比如作为客户端只希望接收来自服务器的数据；而且，因为这个缓存可以被任何信息进入，从而也是一个安全隐患，很可能这个缓存在短时间内就会被垃圾信息所填满。<br>因此，很多时候我们也会用到&#8220;有连接&#8221;的UDP。
<img src ="http://www.cppblog.com/lf426/aggbug/117628.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-11 11:18 <a href="http://www.cppblog.com/lf426/archive/2010/06/11/117628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（五）UDP原理：2、设计UDP client类</title><link>http://www.cppblog.com/lf426/archive/2010/06/10/117584.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 10 Jun 2010 11:37:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/10/117584.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117584.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/10/117584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117584.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117584.html</trackback:ping><description><![CDATA[UDP的客户端看起来几乎就是服务器端的翻版，甚至比服务器端更简单——因为不需要bind()本机地址：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;UDPClientSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock&nbsp;{<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;sockaddr_in&nbsp;lastfromSockAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;destinationSockAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preBufferSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;UDPClientSock(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPClientSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;dest_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;sockaddr_in</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_sock_addr);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPSendtoDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
在最初设计这个类的时候，我曾经考虑过安排一个服务器地址的私有数据成员，并且在构造函数里面指定服务器的地址。但是，后来我觉得使用&#8220;目的地&#8221;比&#8220;服务器&#8221;更加能体现出UDP无连接的本质特点。TCP之所以有个服务器，是因为TCP的客户端只能和自己的服务器端通讯。而UDP的客户端可以与任何一个UDP端口通讯——只要知道对方的地址（IP地址和UDP端口）就可以发送数据包。况且，在网络情况越来越复杂的今天，很多服务器都不仅仅使用一个IP地址或者域名，比如网站和游戏服务器，而对于客户端来说，只是在意连接到了指定的网站，比如google，而并不清楚是连接到google的哪个服务器。程序内部可能会根据网络条件对具体连接的服务器地址进行调整，所以，可以随时根据具体情况指定&#8220;目的地&#8221;，而不是一开始就指定一个&#8220;服务器&#8221;地址，这种策略显得更加灵活。<br>通常情况下，客户端也并不在意lastfromSockAddr，因为最后一次来向的地址，往往就是目的地服务器的地址。我们说过，服务器的端口是指定的，这是为了让客户端明确的知道，可以去连接。而客户端的端口的端口则是系统指定的——我们并没有在客户端调用bind()，所以socket机制会自动帮我们绑定一个端口。通常客户端自己也不需要知道这个端口号是多少，只有接收到这次UDP数据报的服务器端知道，并且按照这个端口号将服务器的信息传送过来——没有收到这个端口发出的数据报的UDP端口很难知道这个系统指定的端口号是多少。但是，因为这个UDP端口实际上是可以接受来自其他任何UDP端口的数据的，所以，如果你需要验证发送某次数据的地址是不是你所期望的，比如是不是来自服务器，可能就会用到lastfromSockAddr。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">UDPClientSock::UDPClientSock(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>preBufferSize(pre_buffer_size),&nbsp;preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preBuffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lastfromSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(lastfromSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">destinationSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(destinationSockAddr));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,&nbsp;SOCK_DGRAM,&nbsp;IPPROTO_UDP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sock()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>UDPClientSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPClientSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;close(sockFD);<br>}</span></div>
其它4个类方法，跟server端的简直一模一样。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPClientSock::UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;dest_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;inet_addr(dest_IP);<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(dest_port);<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPClientSock::UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;sockaddr_in</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_sock_addr)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_family;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_addr.s_addr;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_port;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPClientSock::UDPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;socklen_t</span><span style="COLOR: #000000">&nbsp;from_add_len&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(lastfromSockAddr); <span style="COLOR: #008000">//use int in win32</span><br>&nbsp;&nbsp;&nbsp;&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recvfrom(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBufferSize,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lastfromSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">from_add_len);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPClientSock::UDPSendtoDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;send_message_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;sendto(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_length,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">destinationSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(destinationSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(send_message_size&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(send_message_size&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;sent&nbsp;a&nbsp;different&nbsp;number&nbsp;of&nbsp;bytes&nbsp;than&nbsp;expected.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;send_message_size;<br>}</span></div>
<img src ="http://www.cppblog.com/lf426/aggbug/117584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-10 19:37 <a href="http://www.cppblog.com/lf426/archive/2010/06/10/117584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（五）UDP原理：1、设计UDP server类</title><link>http://www.cppblog.com/lf426/archive/2010/06/10/117549.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 10 Jun 2010 04:16:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/10/117549.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117549.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/10/117549.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117549.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117549.html</trackback:ping><description><![CDATA[<p>人们通常用电话连线来说明TCP协议，而UDP协议，则常常用邮递来做比喻。与TCP有连接的信息传输方式不同，UDP协议被认为是对底层IP协议简单的扩展：协议并不保证每个数据包都会到达目的地，也不保证到达的顺序，而仅仅就是&#8220;尽力&#8221;的发送每一个数据包。我在这篇教程中有时候使用&#8220;数据包&#8221;有时候使用&#8220;数据报&#8221;，广义的说，这两个词意思类似，有代表一个有大小边缘的数据块。但是，用&#8220;数据包&#8221;的时候，我想强调的是这个数据块中所传送的数据部分；而&#8220;数据报&#8221;则更强调在数据块中对这段数据的信息和说明部分，比如IP首部，TCP和UDP首部，TCP和UDP报文段这些信息。TCP协议通过同步验证实现了TCP层面上的&#8220;数据流&#8221;传送，而下层的IP协议，依然是数据报形式的传送，这个我们在前面已经描述过，比如连接握手和断开握手，实际上都是发送的TCP数据报（TCP格式的IP数据报）。UDP格式的IP数据报为IP数据报指定了UDP端口，从而使这样的IP数据报的目的地能够精确到应用程序——没有端口指定的IP数据报目的地只能精确到具有IP地址的主机。另外，与TCP的无边缘保证相反，UDP数据包是有大小的，而其最大限制也即是IP数据包大小的最大限制：65,507字节（这里需要说明两点：1、IP数据包的理论最大值为2^16 - 1，即65,535字节，UDP数据报因为要包含UDP首部的信息，所以比这个值小一点；2、因为MTU的存在，实际传输中的IP数据包会被分封到1500字节以下。）<br>因为UDP是无连接的，就像一个邮筒，可以接受来自任何人的邮件；也可以发送给任何人的邮件。而每一次接受，都会得到来向的地址；每一次发送，也必须指明去向的地址。我们设计一个类，分别以lastfromSockAddr和destinationSockAddr表示最后一次来向的地址以及（下一次发送的）目的地地址。需要指出的是，因为防火墙的普遍存在，最后一次来向地址变得极其重要！这一点我们将在后面的讨论中看到。</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;UDPServerSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock&nbsp;{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;serverSockAddr;<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;sockaddr_in&nbsp;lastfromSockAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;destinationSockAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preBufferSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;UDPServerSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPServerSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;dest_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;sockaddr_in</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_sock_addr);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPSendtoDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
我们把最后一次来向地址以及预接收缓存中的收到的数据长度设置成mutable是因为我们希望接收UDPReceive()这个方法看起来是不改变对象的。每一次接收，实际上都会刷新lastfromSockAddr，而作为服务器，往往也是通过lastfromSockAddr去决定destinationSockAddr的。
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">UDPServerSock::UDPServerSock(unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>preBufferSize(pre_buffer_size),&nbsp;preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preBuffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">serverSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lastfromSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(lastfromSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">destinationSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(destinationSockAddr));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(server_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,&nbsp;SOCK_DGRAM,&nbsp;IPPROTO_UDP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sock()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(bind(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">serverSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>UDPServerSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">UDPServerSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;close(sockFD);<br>}</span></div>
构造函数依然使用socket()建立sockFD，然后通过bind()将本机的SockAddr（主要是指定了端口）绑定到这个sockFD上。<br>我们重载了UDPSetDest()这个方法，可以有两种方式去指定目标地址destinationSockAddr——既可以指定IP地址和端口，也可以直接赋值以sockaddr_in结构。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPServerSock::UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;dest_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;inet_addr(dest_IP);<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(dest_port);<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;UDPServerSock::UDPSetDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;sockaddr_in</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;dest_sock_addr)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_family;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_addr.s_addr;<br>&nbsp;&nbsp;&nbsp;&nbsp;destinationSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;dest_sock_addr.sin_port;<br>}</span></div>
最后是接收和发送。我们知道TCP里面recv()返回0表示连接正常断开，而UDP里面，则仅仅就是表示收到0字节的数据包。可见，数据大小为0，并不代表数据包为空，因为这个数据包实际也是一个数据报，包含着TCP数据报的各种必要信息。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPServerSock::UDPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;socklen_t</span><span style="COLOR: #000000">&nbsp;from_add_len&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(lastfromSockAddr); <span style="COLOR: #008000">//use int in win32</span><br>&nbsp;&nbsp;&nbsp;&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recvfrom(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBufferSize,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lastfromSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">from_add_len);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;UDPServerSock::UDPSendtoDest(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;send_message_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;sendto(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_length,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">destinationSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(destinationSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(send_message_size&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(send_message_size&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;sent&nbsp;a&nbsp;different&nbsp;number&nbsp;of&nbsp;bytes&nbsp;than&nbsp;expected.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;send_message_size;<br>}</span></div>
<img src ="http://www.cppblog.com/lf426/aggbug/117549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-10 12:16 <a href="http://www.cppblog.com/lf426/archive/2010/06/10/117549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（四）TCP应用：2、构建echo客户端</title><link>http://www.cppblog.com/lf426/archive/2010/06/08/117362.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Tue, 08 Jun 2010 03:49:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/08/117362.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117362.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/08/117362.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117362.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117362.html</trackback:ping><description><![CDATA[echo客户端的工作原理也很简单：<br>1、向服务器端发送一个字符串；<br>2、接收服务器的返回信息（如果是echo服务器就会返回发送出去的字符串本身）。<br>3、在标准输出中回显服务器返回的信息。<br>与ehco服务器类似，我们的echo客户端类也可以从TCPClientSock中派生出来：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename&nbsp;AppSock.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;APP_SOCK_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;APP_SOCK_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPEchoClient:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;TCPClientSock{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoClient(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;server_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoClient();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;doEcho(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;echo_message)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">AppSock.hpp</span></div>
我们的doEcho()接收一个C++风格的字符串（std::string），将返回值设计成bool是出于以下考虑：我们希望与服务器断开连接的信息能反馈到主程序中，并且在断开连接后终止echo客户端的程序。所以，返回true表示仍然与服务器保持连接，否则则已经断开（或者异常）。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br>TCPEchoClient::TCPEchoClient(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;server_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>TCPClientSock(server_IP,&nbsp;server_port,&nbsp;pre_buffer_size)<br>{}<br><br>TCPEchoClient::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoClient()<br>{}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;TCPEchoClient::doEcho(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;echo_message)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(TCPSend(echo_message.data(),&nbsp;echo_message.size())&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;total_received_length&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(total_received_length&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;echo_message.size())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(TCPReceive()&nbsp;</span><span style="COLOR: #000000">&lt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout.write(preBuffer,&nbsp;preReceivedLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total_received_length&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>}</span></div>
因为我们是先发再收，我们接收前是知道应该收到多少字节的信息的。由于TCP协议对边缘的无保障，我们应该假定是是最不利的情况，也就是一次recv()不能接收完我们需要的数据，所以，如果接收到的字节数小于我们的预期，就再次接收，直到跟我们发送的字符串长度一样。虽然事实上在这种小数据的传输中很难遇到以上所描述的那种情况，但是在网络程序的设计中，应该坚持这样一个基本假设：你永远不知道远程的主机会出什么状况，所以永远以最坏的可能性来设计程序。<br>最后是主程序。主程序在标准输入中阻塞等待用于echo的信息，为了避免无限循环，我们也设计一个可以关闭服务器端的命令/exit。这样，输入/exit或者服务器断开都可以导致客户端终止。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">])&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;WinsockAPI&nbsp;winsockInfo;<br>&nbsp;&nbsp;&nbsp;&nbsp;winsockInfo.showVersion();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoClient&nbsp;echo_client(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">],&nbsp;server_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(msg&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/exit</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Echo:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::getline(std::cin,&nbsp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_client.doEcho(msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
本节源代码下载：<br>linux:<br><a href="http://www.163pan.com/files/c0x000g0x.html">http://www.163pan.com/files/c0x000g0x.html</a><br>win32:<br><a href="http://www.163pan.com/files/c0x000g0y.html">http://www.163pan.com/files/c0x000g0y.html</a>
<img src ="http://www.cppblog.com/lf426/aggbug/117362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-08 11:49 <a href="http://www.cppblog.com/lf426/archive/2010/06/08/117362.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（四）TCP应用：1、构建echo服务器</title><link>http://www.cppblog.com/lf426/archive/2010/06/08/117357.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Tue, 08 Jun 2010 02:56:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/08/117357.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117357.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/08/117357.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117357.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117357.html</trackback:ping><description><![CDATA[现在，我们用前面所构建的socket类，重新设计第一章中echo的服务器，然后设计客户端程序。<br>echo服务器的工作原理很简单：<br>1、接收客户端传来的信息；<br>2、将接收到的信息原封不动的返回给客户端。<br>可以看到我们所设计的TCPServerSock类具备了echo服务的所有数据成员，我们只需要添加一个具体的echo方法。因此，我们让设计的echo类从TCPServerSock类中派生出来。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename&nbsp;AppSock.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;APP_SOCK_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;APP_SOCK_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPEchoServer:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;TCPServerSock{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoServer(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoServer();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;handEcho()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">AppSock.hpp</span></div>
将handEcho()设计成返回值为bool是出于以下考虑：因为服务器端通常是无限循环提供服务的，我们希望客户端能简单的对服务器端的控制，比如说进行关闭，这样就不用每次用Ctrl+c来关闭服务器端的程序。所以，handlEcho()返回true表示客户端正常断开，false表示服务器被要求终止。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;AppSock.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br>TCPEchoServer::TCPEchoServer(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>TCPServerSock(listen_sock,&nbsp;pre_buffer_size)<br>{}<br><br>TCPEchoServer::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoServer()<br>{}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;TCPEchoServer::handEcho()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/shutdown</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(TCPReceive()&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;cmd(preBuffer,&nbsp;SHUTDOWN_CMD.size());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(cmd&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)SHUTDOWN_CMD.size())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCPSend(preBuffer,&nbsp;preReceivedLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>}</span></div>
我们为服务器指定一个关闭的的特殊字符串/shutdown，如果客户端传来这个字符串，服务器就会终止；其他字符串则会履行echo服务。<br>最后我们设计主程序：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;main.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">])&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;TCPListenSock&nbsp;listen_sock(listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;listen_sock.TCPListen();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(go_on){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoServer&nbsp;echo_server(listen_sock);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_server.handEcho();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
主程序以第一个参数（argv[1]）来指定服务器端口，如果不指定，则默认端口是5000。&nbsp;<br>本节源代码下载：<br>Linux:<br><a href="http://www.163pan.com/files/c0x000g0o.html">http://www.163pan.com/files/c0x000g0o.html</a><br>win32:<br><a href="http://www.163pan.com/files/c0x000g0q.html">http://www.163pan.com/files/c0x000g0q.html</a>
<img src ="http://www.cppblog.com/lf426/aggbug/117357.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-08 10:56 <a href="http://www.cppblog.com/lf426/archive/2010/06/08/117357.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：7、TCP连接的关闭</title><link>http://www.cppblog.com/lf426/archive/2010/06/07/117340.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 07 Jun 2010 12:58:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/07/117340.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117340.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/07/117340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117340.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117340.html</trackback:ping><description><![CDATA[TCP连接一旦建立，服务器端和客户端就成为了对等关系，任何一方都可以发出关闭握手请求，甚至可以同时发出关闭握手请求。TCP的连接建立需要3次握手，而正常关闭则需要4次握手。<br>1、主动关闭的一方A调用close()，SendQ不再接收send()写入信息，在SendQ队列的最后，向被动关闭的一方发送TCP的IP数据报作为关闭握手的请求。这个数据报中包含着标志FIN，也包含着此刻的字节序号m。<br>2、B接收到第一次关闭握手请求后马上返回一个数据报作为回应。因为B接收到了FIN作为关闭连接的一个字节的数据，所以返回的字节序号是m+1。当A接收到B的这个回应，也即是第二次握手以后，表明确认在A到B的方向上不再有数据传送，A即转入所谓半关闭状态，等待B的关闭请求。而B收到FIN会导致recv()返回零，让应用层知道A到B的连接已经断开。<br>3、B方通知了应用层后也就进入等待关闭的状态。当B开始进入关闭流程，也会由B向A发送一个FIN，同时包含着B到A通讯方向上此刻的字节序号n。<br>4、A接收到B的这个FIN之后，也会将序号n+1反馈给B，自此，表明B到A的方向上不再有数据传送，TCP连接正式成功关闭。<br>以上只是对TCP连接关闭的简单描述，事实上，除了使用close()关闭，还可以使用shutdown()，这样在&#8220;半关闭&#8221;状态下还可以对TCP做其他的利用，具体内容就请大家自己查阅相关资料了。<br>最后，送上本人对于TCP连接的理解——&#8220;双向的单行道&#8221;——分别建立连接，也分别断开连接。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p06.jpg" width=620 height=232>
<img src ="http://www.cppblog.com/lf426/aggbug/117340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-07 20:58 <a href="http://www.cppblog.com/lf426/archive/2010/06/07/117340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：6、字节流的发送与接收</title><link>http://www.cppblog.com/lf426/archive/2010/06/07/117336.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 07 Jun 2010 12:09:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/07/117336.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117336.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/07/117336.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117336.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117336.html</trackback:ping><description><![CDATA[从TCP三次握手的原理我们可以看到，TCP有&#8220;保障&#8221;的连接实际上可以看做是两个单向的连接：一个通道只负责发送，另外一个只负责接收。并且，传送的信息是以字节为单位保证顺序的。<br>在socket机制中，应用层的程序以send()函数将数据首先发送到本机系统的发送缓存中，我们称之为SendQ，意指这是一个FIFO（先进先出）的队列。这个缓存是系统决定的，并不是在我们的程序中指定的。然后socket机制负责将SendQ中的数据以字节为单位，按照顺序发送给对方的接收缓存RecvQ中。RecvQ也是一个属于系统的FIFO缓存队列。从程序员的角度看，send()函数只负责把数据送入SendQ，而SendQ何时将数据发送则是不可控的。所以，send()通常不会阻塞，只有在不能立即将数据发送给SendQ的时候才会阻塞，这往往是因为SendQ缓存已满。另外，SendQ并不负责统计每次send()所发送来的字节流的长度，事实上这个长度在TCP中没有意义，因为所有数据都以字节为单位按照FIFO的形式排列在队列中，而并不在乎来自于哪一次的send()。这也就是所谓的TCP无边缘保证，TCP的send()并不在乎每次传送的数据有多少，而只是致力于将数据以字节为单位按照FIFO的形式排列在SendQ队列中。我们看一下TCPServerSock和TCPClientSock的TCPSend()方法：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPServerSock::TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(data_length&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;preBufferSize)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Data&nbsp;is&nbsp;too&nbsp;large,&nbsp;resize&nbsp;preBufferSize.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sent_length&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;send(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_length,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sent&nbsp;unexpected&nbsp;number&nbsp;of&nbsp;bytes.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;sent_length;<br>}</span></div>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPClientSock::TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(data_length&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;preBufferSize)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Data&nbsp;is&nbsp;too&nbsp;large,&nbsp;resize&nbsp;preBufferSize.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sent_length&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;send(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_length,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sent&nbsp;unexpected&nbsp;number&nbsp;of&nbsp;bytes.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;sent_length;<br>}</span></div>
可以看到，这两个方法除了分属于不同的类名字不一样，其他都是一样的。send()的返回值是实际发送的字节长度。<br>在收信息的另外一边，当RecvQ没有数据时，recv()就会阻塞（默认情况下），每当有数据可接收，recv()就会返回实际接收到的数据长度。recv()同样不在乎每次接收的数据有多少，其参数只有一个最大长度限制，这个限制是应用程序分配给每次recv()储存数据的缓存大小。所以TCP的send()和recv()不是一一对应的：send()只负责将数据写入本机的SendQ，而recv()只负责把本机RecvQ中的数据读出来。假设send()传送了m+n字节，但是第一次到达远程目的地的RecvQ中只有m字节，于是这里的recv()就会马上返回m字节；剩下的n字节第二次才姗姗来迟，那么就需要第二次调用recv()来接收。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPServerSock::TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBufferSize,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client&nbsp;has&nbsp;been&nbsp;disconnected.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>}</span></div>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPClientSock::TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBufferSize,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Disconnected&nbsp;from&nbsp;server.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>}</span></div>
可以看到这2个方法也几乎是一模一样——除了名字和对异常信息的描述。因为我们这里并不知道需要recv()的确切长度，所以这里的TCPReceive()也跟recv()一样，有数据就返回。需要验证数据长度的，比如echo服务，我们另外写验证长度的代码。<br>最后需要说明的是，虽然SYN和FIN都会占用一个字节的数据，但是对于应用层的send()和recv()来说是不可见的。FIN会让recv()返回0，表示连接正常断开。
<img src ="http://www.cppblog.com/lf426/aggbug/117336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-07 20:09 <a href="http://www.cppblog.com/lf426/archive/2010/06/07/117336.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：5、TCP的三次握手（three-way handshake）</title><link>http://www.cppblog.com/lf426/archive/2010/06/07/117313.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 07 Jun 2010 05:16:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/07/117313.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117313.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/07/117313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117313.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117313.html</trackback:ping><description><![CDATA[前面3个小节介绍了socket机制对TCP协议三次握手的实现，需要强调的是，与协议独立于实现类似，TCP的三次握手是独立于socket体系的理论。在TCP协议中，三次握手是通过3个TCP格式的IP数据报来实现的。TCP格式的IP数据报中包含着TCP首部，TCP首部信息中包含着对每一个数据报具体内容的描述。我们这里需要介绍的首部位（bit）标志只有3个：<br>SYN：同步序号用来发起一个连接。因为TCP协议要求数据传送是可靠的，他的实现方式就是对传输的数据的每一个字节（byte）按顺序编号。但是初始序列号（ISN：Initial Sequence Number）并非从0开始，而是一个随时间周而复始变化的32位无符号整数。当一方发起连接的时候，SYN就会被设置成1，同时，在发送的数据部分用一个字节来表明这是一个新连接的开始。因此，假设发起连接的一方的ISN为n，因为SYN会在数据部分添加一个字节表示这是一个新连接的开始，所以这时候的字节序号就成了n+1。<br>ACK：确认序号有效。TCP协议要求自动检验数据的可靠性，实现方式就是检验字节序号是否正确的衔接。假如接收数据的一方序号已经是m，那么其返回给发送方确认有效的序号就是m+1。一旦连接，ACK始终设置为1，即表示序号有效，并且在所有数据包中总是存在。但是数据是否真的被TCP采用要看序号是否能对应。如果发送方传来的字节序号没有从m+1开始，那么这个IP数据包就不会被采用，返回ACK信息序号依然是m+1；如果发送方传来的字节序号尽管是从m+1开始的，但是在效验时发生了错误，这个数据报依然不会被采用，返回的ACK信息序号依然是m+1。直到接收了通过TCP检验的数据，序号才会继续增加，例如，传来的数据字节序号从m+1开始到m+k结束，并且通过了TCP效验，那么再次传回的ACK信息，序号就成为了m+k+1。<br>FIN：发送端完成发送。与SYN类似，FIN也会在数据部分占用一个字节，表示这是一个结束符号。<br>TCP的三次握手过程如下：<br>1、第一个SYN连接请求由客户端发起，这个数据报将SYN设置为1表示是一个连接请求，并且包含着这次连接的ISN，我们假设其值为n。<br>2、服务器端收到第一次握手请求的数据报后开始构建反馈的数据报。反馈数据报包括两个部分：第一部分是将连接请求的序号反馈回去，因为SYN本身占了一个字节，所以反馈回去的序号就是n+1；第二部分是自己也向客户端发起SYN连接请求，也将SYN设置为1，并包含这个新连接的ISN，我们设其值为m。<br>3、客户端回应服务器端的SYN连接请求，将服务器端到客户端连接的序号反馈回去，因为SYN占了一个字节，所以反馈给服务器端的序号是m+1。<br>由此，我们可以看到，TCP中，客户端到服务器端，服务器端到客户端的连接是分别建立的，具有不同的ISN（n和m），我们在后面可以看到，这也就意味着这两个连接在正常情况下需要分别的断开。
<img src ="http://www.cppblog.com/lf426/aggbug/117313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-07 13:16 <a href="http://www.cppblog.com/lf426/archive/2010/06/07/117313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：4、设计TCP socket的类（下）</title><link>http://www.cppblog.com/lf426/archive/2010/06/07/117299.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sun, 06 Jun 2010 16:46:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/07/117299.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117299.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/07/117299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117299.html</trackback:ping><description><![CDATA[在另外一边的客户端，我们分析一下TCPClientSock的建立过程。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPClientSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;serverSockAddr;<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preBufferSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPClientSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;server_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPClientSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
我们看到TCPClientSock的类与TCPServerSock很类似，构造函数的差别是，TCPClientSock需要提供server端的IP地址和端口号。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">TCPClientSock::TCPClientSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">server_IP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;server_port,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>preBufferSize(pre_buffer_size),<br>preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preBuffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br><br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,&nbsp;SOCK_STREAM,&nbsp;IPPROTO_TCP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sock()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">serverSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;inet_addr(server_IP);<br>&nbsp;&nbsp;&nbsp;&nbsp;serverSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(server_port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(connect(sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">serverSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">connect()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>TCPClientSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPClientSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;close(sockFD);<br>}</span></div>
TCPClientSock通过socket()建立起sockFD，然后指定服务器的serverSockAddr，然后通过connect()向serverSockAddr指定的服务器发出握手请求。需要说明的是，调用connect()的时候，系统会检查TCPClientSock的sockFD是否已经绑定了本机的SockAddr，事实上我们也可以通过bind()将本机的IP和指定的端口号绑定在这个sockFD上，但是我们并不关心这个IP地址和端口号（况且很多主机并没有公网IP，特别在中国），所以通常我们不自己去绑定，这样系统就会帮我们完成绑定工作，分配一个空闲的端口号作为本机地址的端口号。<br>这样TCPClientSock具有来向（本机地址，通常由系统自动完成绑定，也可以指定）和去向（指定的server端地址）的地址信息，所以可以收发信息。于是，TCPClientSock发出的第一个数据报是发给server监听socket的握手请求数据报，TCPListenSock接收这个数据报后，将相关信息传递给TCPServerSock建立新的sockFD，我们上一节讲到，这个新的sockFD建立起来之后马上就向client端返回一个数据报：一方面表示接受第一次握手请求，另外一方面发出第二次握手请求。<br>收到第二次握手请求后，connect()才会返回，不然就会阻塞，非常&#8220;尽力&#8221;的去连接server。这个&#8220;尽力&#8221;的程度跟系统有关，在我的试验中，windows下很快，就几秒；而Debian则接近6分钟！<br>connect()返回的同时，向server发出了第三次握手的信息，这个信息是对第二次握手请求的认可。所以，第一次和第二次握手包含着连接的请求；而第二次和第三次握手则包含着对握手请求的认可，他们都是在告诉对方：我知道并同意你连接上我了。<br>至此，TCP三次握手的概念在socket中完整的实现，建立起数据流的TCP通信通道。
<img src ="http://www.cppblog.com/lf426/aggbug/117299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-07 00:46 <a href="http://www.cppblog.com/lf426/archive/2010/06/07/117299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：3、设计TCP socket的类（中） </title><link>http://www.cppblog.com/lf426/archive/2010/06/06/117297.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sun, 06 Jun 2010 15:46:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/06/117297.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117297.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/06/117297.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117297.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117297.html</trackback:ping><description><![CDATA[当激活监听的TCPListenSock等待远程client的connect()握手请求的时候，是调用了accept()并且产生阻塞（默认情况下），如果accept()成功返回意味着conect()握手请求请求成功，这时候就通过accept()产生了一个新的sockFD用于TCP通讯。我们把这个新的sockFD构建为TCPServerSock类：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPServerSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;clientSockAddr;<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preBufferSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;TCPServerSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPServerSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
这里，我们为TCPServerSock预留一个缓存，这个缓存并不是必须的，但是设置这样一个缓存至少有两个好处：<br>1、可以在使用时不必专门为recv()建立缓存；<br>2、类方法TCPReceive()和TCPSend()可以共享这个缓存，在处理很多问题时候很方便，比如echo，就不需要先把recv()的缓存读出来再由send()来发送。<br>将缓存已用长度preReceiveLength加上关键字mutable表示我们不关心这个长度会被更改，我们只在乎有一个缓存可以用，但是实际用了多少不重要，这样我们就可以为接受和发送的类方法加上const。<br>我们回到TCPServerSock的建立，TCPServerSock通过TCPListenSock accept()一个远程的client connect()握手请求而建立，所以，TCPServerSock的构造在默认情况下是阻塞的。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">TCPServerSock::TCPServerSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>preBufferSize(pre_buffer_size),<br>preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preBuffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br><br>&nbsp;&nbsp;&nbsp;&nbsp;socklen_t</span><span style="COLOR: #000000">&nbsp;clientSockAddrLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(clientSockAddr);<br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(&nbsp;&nbsp;&nbsp;&nbsp;listen_sock.showSockFD(),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clientSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clientSockAddrLen);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">accept()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client&nbsp;(IP:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;inet_ntoa(clientSockAddr.sin_addr)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;conneted.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>}<br><br>TCPServerSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPServerSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;close(sockFD);<br>}</span></div>
这里需要注意一个Linux和Windows下的不同：<br>对于sockaddr_in（也包括sockaddr）的大小，被accept()指定的时候，Linux中用的是socklen_t，其实这就是size_t，也就是unsigned int。而WinSock中却用的是int。因为在编译中不会自动转换，所以会提示错误。<br>再次强调，TCPServerSock的sockFD是通过accept()建立的而不是socket()，这也是唯一一个不用socket()建立的sockFD（包括UDP的）。在client发出的connect()握手请求的数据报中，同时包含着client端的地址信息（IP地址和端口）和server端的地址信息（IP地址和端口），正是这个握手请求数据报中的两边的地址信息通过accept()被传递到TCPServerSock的sockFD中。请注意，server端的信息并非由TCPListenSock提供，因为TCPListenSock中listenSockAddr的IP地址为空（INADDR_ANY == 0），而TCPServerSock中server端的SockAddr却是具体的，由客户端的握手协议传来的（但是没有具体的体现出来）。只有具体的地址（IP地址和端口）才能提供IP数据包的目的地方向。而端口号，则因为client事先知道监听端口号，从而在握手请求中包含，最终传递给TCPListenSock中server端的SockAddr，虽然这个过程决定了这个端口号等于监听端口号，但是需要明白的是，这个端口号来自握手请求的数据报而不是TCPListenSock的listenSockAddr。<br>新的sockFD具有来向（本机）和去向（远程）的信息，所以可以收发数据。TCPServerSock的sockFD一旦建立，马上向远程返回一个数据报，这个数据报有两层意义：<br>1、表示server已经接收了client的握手请求；<br>2、对client发出与server这个新sockFD握手的请求。<br>这就是所谓第二次握手，并且也是以数据报的形式传送的。我们说过，TCP协议的目标是建立&#8220;可靠&#8221;的数据流形式的通讯，在这个数据流的通道建立起来以前，只能采用数据报的形式传送数据。
<img src ="http://www.cppblog.com/lf426/aggbug/117297.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-06 23:46 <a href="http://www.cppblog.com/lf426/archive/2010/06/06/117297.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：2、设计TCP socket的类（上）</title><link>http://www.cppblog.com/lf426/archive/2010/06/06/117289.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sun, 06 Jun 2010 14:24:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/06/117289.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117289.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/06/117289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117289.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117289.html</trackback:ping><description><![CDATA[我们在第1节中讲过，socket是一个int的文件描述符（WinSock中直接是一种抽象的描述符），我们通过对这个描述符发出指令操作socket。这是C语言的思想，在面向对象的思想中，最好socket本身是一种对象，各种方法由对象本身发出。用面向对象的思想封装socket并不困难，而且，对于描述socket的概念可能更加直观，这一节，我们边介绍socket和TCP的概念边对socket进行OO封装。<br>首先，每一个socket对象都具有唯一的socket文件描述符，这样可以很好的对应socket的概念。所以我们构建一个基类，并让其成为纯虚函数——这是因为socket文件描述符必须在具体的构造中才能出现，然后仍然保留一个返回原始的socket文件描述符的接口，这是为了不方便归结到类函数中的函数所预留准备的，比如极其重要的select()我们会在后面讲到，所谓有备无患。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sockFD;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;BaseSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">BaseSock()&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;showSockFD()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br></span></div>
函数实现：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;BaseSock</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>BaseSock::BaseSock():<br>sockFD(</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br>{}<br><br>BaseSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">BaseSock()<br>{}<br><br></span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;BaseSock::showSockFD()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;sockFD;<br>}</span></div>
我们把sockFD的初始值设置为-1，表明在没有派生类构造的时候这是一个非法的文件描述符号（File Descriptor）。<br>接下来，我们简单回顾一下第一节对于TCP Server的建立：<br>首先，我们需要建立一个监听socket，然后激活其监听；<br>然后，在client端连接信息过来之后，通过监听端口将客户端的信息传递给新的socket，从而建立通讯socket。<br>我们先构建listen socket：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPListenSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;listenSockAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000">&nbsp;TCPListenSock(unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TCPListen(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;max_connection_requests&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
TCPListenSock建立的目的的就是被动的等待client端寻找握手的connect()，从而收集client端的sock地址信息（包含了IP地址和端口号），然后在需要的时候传递给新的socket建立通讯socket。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">TCPListenSock::TCPListenSock(unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCK_STREAM,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPPROTO_TCP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">listenSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(bind(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">listenSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>TCPListenSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;close(sockFD);<br>}</span></div>
TCPListenSock通过调用socket()建立sockFD；通过指定端口好指明监听端口，这是为客户端能够找到这个端口所必须的。而IP地址设置为INADDR_ANY，其实就是0，这意味着可以是任何一个server端所拥有的IP。TCPListenSock通过bind()将sockFD和SockAddr绑定在一起。这个sockFD只有本机的SockAddr意味着：1、无法建立连接，只有接受数据报；2、只能接受信息，因为没有远程目的地的SockAddr而无法发出信息。<br>而这对于TPC建立连接的过程来说，既是足够的，也是必须的。事实上，client端发出的第一个握手数据报就被这个sockFD所接收，而返回给client的握手应答和对client的握手请求则由新的sockFD发出。<br>listen()是将TCPListenSock激活为监听状态，如果不激活，那么任何握手的连接请求都将被这个sockFD所忽略。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TCPListenSock::TCPListen(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;max_connection_requests)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(listen(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max_connection_requests)&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
这个函数看来似乎有些多此一举，因为这个监听是可以整合到构造函数中的，也就是说，我们可以一旦建立TCPListenSock就令其激活，事实上这正是SDL_net中的做法，也是让我感到不严谨的地方，因为监听本身是socket的一个概念。
<img src ="http://www.cppblog.com/lf426/aggbug/117289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-06 22:24 <a href="http://www.cppblog.com/lf426/archive/2010/06/06/117289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（三）TCP原理：1、socket异常信息</title><link>http://www.cppblog.com/lf426/archive/2010/06/06/117284.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sun, 06 Jun 2010 13:07:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/06/117284.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117284.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/06/117284.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117284.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117284.html</trackback:ping><description><![CDATA[之所以把对异常信息的介绍放到原理之前讲，是因为由于socket本身的复杂性，导致了产生各种异常的复杂性。我们应该时刻铭记的是，sokcet本身属于系统（OS），是系统对TCP/IP的实现，也就是说，socket发出的异常信息不代表程序出错，甚至不代表系统出错，而仅仅就是代表socket本身的各种异常情况。另外一点我觉得应该强调的是：socket不是TCP/IP；TCP/IP也不是socket。socket是为广泛的协议设计的，涉及TCP/IP的内容只是socket体系中一个很小的子集；而TCP/IP就更加独立于sokcet而存在——TCP/IP是协议描述；socket是对协议理论的一种实现形式。<br>因为socket是属于系统的，所以不同的系统对于socket有着大同小异的解释，出错描述也不尽相同。在Linux中，socket的异常信息可以通过errno获得（int类型），然后可以通过函数strerror()将int转换成字符串描述；也可以通过函数perror()直接获得其描述。<br>要使用errno需要包含头文件&lt;errno.h&gt;。我建议使用errno获得int类的错误信息的一个重要原因在于，socket的异常不一定就必然导致程序终止。Bjarne Stroustrup在介绍C++异常机制的时候对C风格的异常机制有着这样的描述：（C++对于异常）的默认响应方式是终止程序。传统的反应（对于发生异常的时候）则是装糊涂，接着做下去，以期得到最好的结果（《C++程序设计语言》第14章 异常处理）。不过以我目前的水平看来，终止正在进行的程序然后再通过异常机制重新启动一个新的流程，其代价远远大于&#8220;装糊涂&#8221;的让程序继续运行下去，只要错误不是致命的，通过简单的判断和处理或许效果更佳。<br>例如，socket中就有一个很有代表性的情况，在TCP连接中，如果一方意外退出——也就是说没有通过TCP退出流程退出，比如没有运行完程序关闭掉socket而直接X掉或者Ctrl+c了。socket往往会因为recv()返回值小于0而抛出一个异常。正常断开连接的时候，recv()会通过返回0表示连接已经断开，但是大多数时候，我们并不希望因为异常的断开就导致另外一端的程序终止（想象一下如果你关掉QQ腾讯的服务器程序就终止是什么概念&#8230;&#8230;），所以我们必须处理这种情况。<br>在Linux中，远程连接异常断开（被重置）的errno代码是104，类似的，我们应该保证出现这种异常的时候程序可以继续运行。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;SockClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;SOCK_CLASS_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;SOCK_CLASS_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">errno.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s);<br>}</span></div>
以上是头文件中的声明，下面是函数，我们这里仅仅演示处理了104错误。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;err_info&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;errno;<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;strerror(err_info)&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">:&nbsp;errno:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;err_info&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(err_info&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">104</span><span style="COLOR: #000000">){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;exit(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>}<br>}</span></div>
在windows中，错误代码由WSAGetLastError()获得，而无需设置errno。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;SockClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;SOCK_CLASS_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;SOCK_CLASS_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">winsock2.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s);<br>}</span></div>
WinSock的错误代码跟Linux中的不一样，同样的异常，WinSock的错误代码是10054。<br>并且，由于没有errno也就无从调用strerror()，我们最好自己写出详细的异常信息。<br>WinSock的详细代码信息在这里：<br><a href="http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx</a><br>win32下的演示代码如下：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;winsock_err&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;perror(s);<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">WinSock&nbsp;Error:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;winsock_err&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(winsock_err&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;WSAECONNRESET)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Connection&nbsp;reset&nbsp;by&nbsp;peer.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;exit(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>}<br>}</span></div>
<img src ="http://www.cppblog.com/lf426/aggbug/117284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-06 21:07 <a href="http://www.cppblog.com/lf426/archive/2010/06/06/117284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（二）winsock演示程序：TCP Server</title><link>http://www.cppblog.com/lf426/archive/2010/06/03/117076.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 03 Jun 2010 02:45:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/03/117076.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117076.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/03/117076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117076.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117076.html</trackback:ping><description><![CDATA[<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;SockClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;SOCK_CLASS_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;SOCK_CLASS_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">winsock2.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s);<br>}<br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;WinsockAPI{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;WSADATA&nbsp;wsaData;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;WinsockAPI(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;low_byte&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;high_byte&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">WinsockAPI();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;showVersion()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sockFD;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;BaseSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">BaseSock()&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;showSockFD()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPListenSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;listenSockAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPListenSock(unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TCPListen(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;max_connection_requests&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPServerSock:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;clientSockAddr;<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preBufferSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;mutable&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPServerSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPServerSock();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SockClass.hpp</span></div>
<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;SockClass.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">sockClass</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;sockClass<br>{<br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;error_info(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;s&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;WSAGetLastError();<br>}<br>}<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;WinsockAPI</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>WinsockAPI::WinsockAPI(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;low_byte,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;high_byte)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;WORD&nbsp;wVersionRequested&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MAKEWORD(low_byte,&nbsp;high_byte);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;wsa_startup_err&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAStartup(wVersionRequested,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">wsaData);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(wsa_startup_err&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">WSAStartup()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;wsa_startup_err;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>WinsockAPI::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">WinsockAPI()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;WSACleanup();<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;WinsockAPI::showVersion()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">The&nbsp;version&nbsp;of&nbsp;Winsock.dll&nbsp;is&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">(LOBYTE(wsaData.wVersion))&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">(HIBYTE(wsaData.wVersion))&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>}<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;BaseSock</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>BaseSock::BaseSock():<br>sockFD(</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br>{}<br><br>BaseSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">BaseSock()<br>{}<br><br></span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;BaseSock::showSockFD()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;sockFD;<br>}<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;TCPListenSock</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>TCPListenSock::TCPListenSock(unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCK_STREAM,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPPROTO_TCP);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">listenSockAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;&nbsp;listenSockAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(bind(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">listenSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>TCPListenSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;closesocket(sockFD);<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TCPListenSock::TCPListen(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;max_connection_requests)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(listen(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max_connection_requests)&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;TCPServerSock</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>TCPServerSock::TCPServerSock(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>preBufferSize(pre_buffer_size),<br>preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preBuffer&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;clientSockAddrLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(clientSockAddr);<br>&nbsp;&nbsp;&nbsp;&nbsp;sockFD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(&nbsp;&nbsp;&nbsp;&nbsp;listen_sock.showSockFD(),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clientSockAddr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clientSockAddrLen);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sockFD&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">accept()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client&nbsp;(IP:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;inet_ntoa(clientSockAddr.sin_addr)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;conneted.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>}<br><br>TCPServerSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPServerSock()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;[]&nbsp;preBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;closesocket(sockFD);<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPServerSock::TCPReceive()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preBufferSize,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client&nbsp;has&nbsp;been&nbsp;disconnected.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;preReceivedLength;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCPServerSock::TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(data_length&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;preBufferSize)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Data&nbsp;is&nbsp;too&nbsp;large,&nbsp;resize&nbsp;preBufferSize.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sent_length&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;send(&nbsp;&nbsp;&nbsp;&nbsp;sockFD,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_data,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data_length,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(sent_length&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;data_length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sent&nbsp;unexpected&nbsp;number&nbsp;of&nbsp;bytes.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;sent_length;<br>}<br></span></div>
<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename&nbsp;AppSock.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;APP_SOCK_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;APP_SOCK_HPP</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TCPEchoServer:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;TCPServerSock{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoServer(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoServer();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;handEcho()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">AppSock.hpp</span></div>
<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;AppSock.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br>TCPEchoServer::TCPEchoServer(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;TCPListenSock</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;listen_sock,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;pre_buffer_size):<br>TCPServerSock(listen_sock,&nbsp;pre_buffer_size)<br>{}<br><br>TCPEchoServer::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPEchoServer()<br>{}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;TCPEchoServer::handEcho()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">/shutdown</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(TCPReceive()&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;cmd(preBuffer,&nbsp;SHUTDOWN_CMD.size());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(cmd&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;preReceivedLength&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;SHUTDOWN_CMD.size())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCPSend(preBuffer,&nbsp;preReceivedLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>}<br></span></div>
<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;main.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SockClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">AppSock.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCP_echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[]);<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;mainRtn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainRtn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">TCP_echo_server(argc,&nbsp;argv);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror(s);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;err)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Error:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;err&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;mainRtn;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;TCP_echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;listen_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;DEFAULT_PORT;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">])&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;WinsockAPI&nbsp;winsockInfo;<br>&nbsp;&nbsp;&nbsp;&nbsp;winsockInfo.showVersion();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;TCPListenSock&nbsp;listen_sock(listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;listen_sock.TCPListen();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(go_on){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCPEchoServer&nbsp;echo_server(listen_sock);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go_on&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_server.handEcho();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}<br></span></div>
<img src ="http://www.cppblog.com/lf426/aggbug/117076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-03 10:45 <a href="http://www.cppblog.com/lf426/archive/2010/06/03/117076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（二）win32下使用socket：WinSock</title><link>http://www.cppblog.com/lf426/archive/2010/06/03/117074.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 03 Jun 2010 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2010/06/03/117074.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/117074.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2010/06/03/117074.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/117074.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/117074.html</trackback:ping><description><![CDATA[学习socket最好能有两台以上联网的电脑，以及能获得公网IP的网络接入方式。两年前，我主要使用的是一台win2k3和Debain Linux双系统的电脑，例外有台99年的老机器装着win98，而且没有装VC，测试相当的麻烦。现在买了笔记本，使用的是Vista的win32环境（32位），可以直接和老电脑的Linux联网进行测试。另外，网络环境也换成了电信的ADSL，贵了很多，为的就是能有一个公网IP。接下来的教程我会兼顾winsock的代码，这主要是因为winsock本身对socket几乎是兼容的。所以，这里有必要先说明在VC环境中使用socket的一些简单设置，以及与Linux环境下的细微差别。<br>我的VC环境依然是2008 Express，在写这篇教程的时候，微软已经发布了VC 2010，目前在微软的官方主页，提供了VC 2010的下载，同时保留着VC 2008的下载。<br>我们在VC中建立一个控制台的空项目：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p01.jpg" width=818 height=621><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p02.jpg" width=634 height=539><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p03.jpg" width=621 height=538><br>我们着手构建自己的第一个winsock程序。<br>首先win32下与Linux下的socket API需要包含不同的头文件。<br>在Linux下是这些：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span></div>
win32下的winsock有多个版本，我所找到的资料中，老的版本是：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">winsock.h</span><span style="COLOR: #000000">&gt;</span></div>
与之对应的需要的链接库为：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p04.jpg" width=422 height=398><br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/lf426/p05.jpg" width=778 height=644><br>这可能可以兼容非常古老的版本中的winsock，比如win98，而微软官方所推荐的是：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">winsock2.h</span><span style="COLOR: #000000">&gt;</span></div>
链接库是：ws2_32.lib，这样就可以使用高版本的winsock。<br>那么，什么是winsock的版本？这就涉及到winsock的初始化函数WSAStartup：<br><a href="http://msdn.microsoft.com/en-us/library/ms742213(v=VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms742213(v=VS.85).aspx</a><br>上面是微软的官方说明，我这里构建一个简单的类，希望每次使用的时候引入一个类对象就可以了。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;WinsockAPI{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;WSADATA&nbsp;wsaData;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;WinsockAPI(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;low_byte&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;high_byte&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">WinsockAPI();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;showVersion()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div>
WSADATA是记录着winsock信息的结构。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">class&nbsp;WinsockAPI</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>WinsockAPI::WinsockAPI(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;low_byte,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;high_byte)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;WORD&nbsp;wVersionRequested&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MAKEWORD(low_byte,&nbsp;high_byte);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;wsa_startup_err&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WSAStartup(wVersionRequested,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">wsaData);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(wsa_startup_err&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cerr&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">WSAStartup()&nbsp;failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;wsa_startup_err;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>WinsockAPI::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">WinsockAPI()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;WSACleanup();<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;WinsockAPI::showVersion()&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">The&nbsp;version&nbsp;of&nbsp;Winsock.dll&nbsp;is&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">(LOBYTE(wsaData.wVersion))&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">(HIBYTE(wsaData.wVersion))&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;std::endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>}</span></div>
首先，宏MAKEWORD()将两个int转换为winsock形式的版本号，我这里默认是是2.2，就只需要MAKEWORD(2, 2)，如果是老版本的，最低应该是1.0。WSAStartup()将winsock的初始化信息写入一个WSADATA结构（我们这里的wsaData），如果成功返回0，失败将返回一个int的错误代码。这个错误代码直接表示了错误信息，微软官方建议不使用winsock的通用异常信息获取函数WSAGetLastError()获取WSAStartup()的错误信息，这可能是因为如果WSAStartup()失败，那么winsock的错误信息不一定能够正确的构建出来的缘故。<br>最后，winsock结束后用WSACleanup()清理。<br>因为socket本身的复杂性，异常信息提示非常重要。WSAGetLastError()的官方说明如下：<br><a href="http://msdn.microsoft.com/en-us/library/ms741580(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms741580(VS.85).aspx</a><br>错误代码所反馈的信息查询在这里：<br><a href="http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx</a><br>最后，需要注意的问题是，因为socket是构建在UNIX系统下的（BSD socket是当今所有socket的基础），所以socket很好的利用了UNIX体系&#8220;一切都是文件&#8221;的性质，每个socket本身也就是一个UNIX文件描述符，因此，Linux下的socket是用关闭文件的函数close()关闭的。但是win32下没这个性质，所以winsock是另外一种抽象，但是好在同样用int作为描述符，关闭需要专门为winsock定做的函数closesocket()。<br>下篇文章重写了TCP Server的代码（类的抽象和构造也重新写了，将在下一章解释），作为winsock使用的演示。
<img src ="http://www.cppblog.com/lf426/aggbug/117074.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2010-06-03 10:37 <a href="http://www.cppblog.com/lf426/archive/2010/06/03/117074.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：8、本章的完整源代码</title><link>http://www.cppblog.com/lf426/archive/2008/07/16/56281.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Wed, 16 Jul 2008 04:57:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/16/56281.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/56281.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/16/56281.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/56281.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/56281.html</trackback:ping><description><![CDATA[<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;TcpServerClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;TCPSERVERCLASS_HPP_INCLUDED<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TCPSERVERCLASS_HPP_INCLUDED</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TcpServer<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listenSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;communicationSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;servAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;clntAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;isAccept();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;handleEcho();<br>};<br><br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;TCPSERVERCLASS_HPP_INCLUDED</span></div>
<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;TcpServerClass.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">TcpServerClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br>TcpServer::TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(listenSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,&nbsp;SOCK_STREAM,&nbsp;IPPROTO_TCP))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">servAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(listen_port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;bind(listenSock,&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">servAddr,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;listen(listenSock,&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;TcpServer::isAccept()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;clntAddrLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(clntAddr);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(communicationSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(listenSock,&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clntAddr,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clntAddrLen))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client(IP:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;inet_ntoa(clntAddr.sin_addr)&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;connected.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TcpServer::handleEcho()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;BUFFERSIZE&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;buffer[BUFFERSIZE];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;recvMsgSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;goon&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(&nbsp;goon&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(recvMsgSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(communicationSock,&nbsp;buffer,&nbsp;BUFFERSIZE,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;recvMsgSize&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goon&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;send(communicationSock,&nbsp;buffer,&nbsp;recvMsgSize,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;recvMsgSize&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;close(communicationSock);<br>}</span></div>
<br>演示程序：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;main.cpp<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Tcp&nbsp;Server&nbsp;C++&nbsp;style,&nbsp;single&nbsp;work</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">TcpServerClass.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[]);<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;mainRtn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainRtn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;echo_server(argc,&nbsp;argv);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">&nbsp;(&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;s&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror(s);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(EXIT_FAILURE);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;mainRtn;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;port;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;argc&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;TcpServer&nbsp;myServ(port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;myServ.isAccept()&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myServ.handleEcho();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div>
<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/56281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-16 12:57 <a href="http://www.cppblog.com/lf426/archive/2008/07/16/56281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：7、接收与发送</title><link>http://www.cppblog.com/lf426/archive/2008/07/16/56279.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Wed, 16 Jul 2008 04:26:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/16/56279.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/56279.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/16/56279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/56279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/56279.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在，我们通过accept()创建了新的socket，也就是我们类中的数据成员communicationSock，现在，我们就可以通过这个socket进行通讯了。<br><br>TCP通讯模型<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在介绍函数之前，我们应该了解一些事实。TCP的Server/Client模型类似这样：<br>ServApp——ServSock——Internet——ClntSock——ClntApp<br>当然，我们这里的socket指的就是用于&#8220;通讯&#8221;的socket。TCP的server端至少有两个socket，一个用于监听，一个用于通讯；TCP的server端可以只有一个socket，这个socket同时&#8220;插&#8221;在server的两个socket上。当然，插上listen socket的目的只是为了创建communication socket，创建完备后，listen是可以关闭的。但是，如果这样，其他的client就无法再连接上server了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们这个模型，是client的socket插在server的communication socket上的示意。这两个socket，都拥有完整的本地地址信息以及远程计算机地址信息，所以，这两个socket以及之间的网络实际上形成了一条形式上&#8220;封闭&#8221;的管道。数据包只要从一端进来，就能知道出去的目的地，反之亦然。这正是TCP协议，数据流形式抽象化以及实现。因为不再需要指明&#8220;出处&#8221;和&#8220;去向&#8221;，对这样的socket（实际上是S/C上的socket对）的操作，就如同对本地文件描述符的操作一样。但是，尽管我们可以使用read()和write()，但是，为了完美的控制，我们最好使用recv()和send()。<br><br>recv()和send()<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;send(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;msg,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;msgLength,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;flags);<br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;recv(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;rcvBuffer,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bufferLength,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;flags);</span></div>
在Linux中的实现为：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Send&nbsp;N&nbsp;bytes&nbsp;of&nbsp;BUF&nbsp;to&nbsp;socket&nbsp;FD.&nbsp;&nbsp;Returns&nbsp;the&nbsp;number&nbsp;sent&nbsp;or&nbsp;-1.<br><br>&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;is&nbsp;a&nbsp;cancellation&nbsp;point&nbsp;and&nbsp;therefore&nbsp;not&nbsp;marked&nbsp;with<br>&nbsp;&nbsp;&nbsp;__THROW.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;ssize_t&nbsp;send&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;__const&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">__buf,&nbsp;size_t&nbsp;__n,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__flags);<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Read&nbsp;N&nbsp;bytes&nbsp;into&nbsp;BUF&nbsp;from&nbsp;socket&nbsp;FD.<br>&nbsp;&nbsp;&nbsp;Returns&nbsp;the&nbsp;number&nbsp;read&nbsp;or&nbsp;-1&nbsp;for&nbsp;errors.<br><br>&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;is&nbsp;a&nbsp;cancellation&nbsp;point&nbsp;and&nbsp;therefore&nbsp;not&nbsp;marked&nbsp;with<br>&nbsp;&nbsp;&nbsp;__THROW.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;ssize_t&nbsp;recv&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">__buf,&nbsp;size_t&nbsp;__n,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__flags);</span></div>
这两个函数的第一个参数是用于&#8220;通讯&#8221;的socket，第二个参数是发送或者接收数据的起始点指针，第三个参数是数据长度，第四个参数是控制符号（默认属性设置为0就可以了）。失败时候传回-1，否则传回实际发送或者接收数据的大小，返回0往往意味着连接断开了。<br><br>处理echo行为<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;TcpServer::handleEcho()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;BUFFERSIZE&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;buffer[BUFFERSIZE];<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;recvMsgSize;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;goon&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(&nbsp;goon&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(recvMsgSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;recv(communicationSock,&nbsp;buffer,&nbsp;BUFFERSIZE,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;recvMsgSize&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goon&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;send(communicationSock,&nbsp;buffer,&nbsp;recvMsgSize,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;recvMsgSize&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;close(communicationSock);<br>}</span></div>
本小节最后要讲的函数是close()，它包含在&lt;unistd.h&gt;中<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Close&nbsp;the&nbsp;file&nbsp;descriptor&nbsp;FD.<br><br>&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;is&nbsp;a&nbsp;cancellation&nbsp;point&nbsp;and&nbsp;therefore&nbsp;not&nbsp;marked&nbsp;with<br>&nbsp;&nbsp;&nbsp;__THROW.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;close&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd);</span></div>
这个函数用于关闭一个文件描述符，自然，也就可以用于关闭socket。<br>下一小节是完整的源代码。默认的监听端口是5000。我们可以通过<br>$telnet 127.0.0.1 5000<br>验证在本机运行的echo server程序。<br>
<img src ="http://www.cppblog.com/lf426/aggbug/56279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-16 12:26 <a href="http://www.cppblog.com/lf426/archive/2008/07/16/56279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：6、创建“通讯 ”嵌套字</title><link>http://www.cppblog.com/lf426/archive/2008/07/15/56180.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Tue, 15 Jul 2008 05:04:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/15/56180.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/56180.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/15/56180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/56180.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/56180.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里的&#8220;通讯&#8221;加上了引号，是因为实际上所有的socket都有通讯的功能，只是在我们的例子中，之前那个socket只负责listen，而这个socket负责接受信息并echo回去。<br>&nbsp;我们现看看这个函数：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;TcpServer::isAccept()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;clntAddrLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(clntAddr);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(communicationSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;accept(listenSock,&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clntAddr,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">clntAddrLen))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client(IP:&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;inet_ntoa(clntAddr.sin_addr)&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)&nbsp;connected.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>用accept()创建新的socket<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在我们的例子中，communicationSock实际上是用函数accept()创建的。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;accept(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;clientAddress,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;addressLength);</span></div>
在Linux中的实现为：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Await&nbsp;a&nbsp;connection&nbsp;on&nbsp;socket&nbsp;FD.<br>&nbsp;&nbsp;&nbsp;When&nbsp;a&nbsp;connection&nbsp;arrives,&nbsp;open&nbsp;a&nbsp;new&nbsp;socket&nbsp;to&nbsp;communicate&nbsp;with&nbsp;it,<br>&nbsp;&nbsp;&nbsp;set&nbsp;*ADDR&nbsp;(which&nbsp;is&nbsp;*ADDR_LEN&nbsp;bytes&nbsp;long)&nbsp;to&nbsp;the&nbsp;address&nbsp;of&nbsp;the&nbsp;connecting<br>&nbsp;&nbsp;&nbsp;peer&nbsp;and&nbsp;*ADDR_LEN&nbsp;to&nbsp;the&nbsp;address's&nbsp;actual&nbsp;length,&nbsp;and&nbsp;return&nbsp;the<br>&nbsp;&nbsp;&nbsp;new&nbsp;socket's&nbsp;descriptor,&nbsp;or&nbsp;-1&nbsp;for&nbsp;errors.<br><br>&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;is&nbsp;a&nbsp;cancellation&nbsp;point&nbsp;and&nbsp;therefore&nbsp;not&nbsp;marked&nbsp;with<br>&nbsp;&nbsp;&nbsp;__THROW.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;accept&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;__SOCKADDR_ARG&nbsp;__addr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socklen_t&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">__restrict&nbsp;__addr_len);</span></div>
这个函数实际上起着构造socket作用的仅仅只有第一个参数（另外还有一个不在这个函数内表现出来的因素，后面会讨论到），后面两个指针都有副作用，在socket创建后，会将客户端sockaddr的数据以及结构体的大小传回。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当程序调用accept()的时候，程序有可能就停下来等accept()的结果。这就是我们前一小节说到的block（阻塞）。这如同我们调用std::cin的时候系统会等待输入直到回车一样。accept()是一个有可能引起block的函数。请注意我说的是&#8220;有可能&#8221;，这是因为accept()的block与否实际上决定与第一个参数socket的属性。这个文件描述符如果是block的，accept()就block，否则就不block。默认情况下，socket的属性是&#8220;可读可写&#8221;，并且，是阻塞的。所以，我们不修改socket属性的时候，accept()是阻塞的。<br><br>accept()的另一面connect()<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accept()只是在server端被动的等待，它所响应的，是client端connect()函数：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;connect(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;foreignAddress,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;addressLength);</span></div>
虽然我们这里不打算详细说明这个client端的函数，但是我们可以看出来，这个函数与之前我们介绍的bind()有几分相似，特别在Linux的实现中：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Open&nbsp;a&nbsp;connection&nbsp;on&nbsp;socket&nbsp;FD&nbsp;to&nbsp;peer&nbsp;at&nbsp;ADDR&nbsp;(which&nbsp;LEN&nbsp;bytes&nbsp;long).<br>&nbsp;&nbsp;&nbsp;For&nbsp;connectionless&nbsp;socket&nbsp;types,&nbsp;just&nbsp;set&nbsp;the&nbsp;default&nbsp;address&nbsp;to&nbsp;send&nbsp;to<br>&nbsp;&nbsp;&nbsp;and&nbsp;the&nbsp;only&nbsp;address&nbsp;from&nbsp;which&nbsp;to&nbsp;accept&nbsp;transmissions.<br>&nbsp;&nbsp;&nbsp;Return&nbsp;0&nbsp;on&nbsp;success,&nbsp;-1&nbsp;for&nbsp;errors.<br><br>&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;is&nbsp;a&nbsp;cancellation&nbsp;point&nbsp;and&nbsp;therefore&nbsp;not&nbsp;marked&nbsp;with<br>&nbsp;&nbsp;&nbsp;__THROW.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;connect&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;__CONST_SOCKADDR_ARG&nbsp;__addr,&nbsp;socklen_t&nbsp;__len);</span></div>
connect() 也使用了const的sockaddr，只不过是远程电脑上的而非bind()的本机。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accept()在server端表面上是通过listen socket创建了新的socket，实际上，这种行为是在接受对方客户机程序中connect()函数的请求后发生的。综合起看，被创建的新socket实际上包含了listen socket的信息以及客户端connect()请求中所包含的信息——客户端的sockaddr地址。<br><br>新socket与sockaddr的关系<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; accept()创建的新socket（我们例子中的communicationSock，这里我们简单用newSock来带指）首先包含了listen socket的信息，所以，newSock具有本机sockaddr的信息；其次，因为它响应于client端connect()函数的请求，所以，它还包含了clinet端sockaddr的信息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们说过，stream流形式的TCP协议实际上是建立起一个&#8220;可来可去&#8221;的通道。用于listen的通道，远程机的目标地址是不确定的；但是newSock却是有指定的本机地址和远程机地址，所以，这个socket，才是我们真正用于TCP&#8220;通讯&#8221;的socket。<br><br>inet_ntoa()<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Convert&nbsp;Internet&nbsp;number&nbsp;in&nbsp;IN&nbsp;to&nbsp;ASCII&nbsp;representation.&nbsp;&nbsp;The&nbsp;return&nbsp;value<br>&nbsp;&nbsp;&nbsp;is&nbsp;a&nbsp;pointer&nbsp;to&nbsp;an&nbsp;internal&nbsp;array&nbsp;containing&nbsp;the&nbsp;string.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">inet_ntoa&nbsp;(</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr&nbsp;__in)&nbsp;__THROW;</span></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于这个函数，我们可以作为一种，将IP地址，由in_addr结构转换为可读的ASCII形式的固定用法。<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/56180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-15 13:04 <a href="http://www.cppblog.com/lf426/archive/2008/07/15/56180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：5、创建监听嵌套字</title><link>http://www.cppblog.com/lf426/archive/2008/07/14/56092.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 14 Jul 2008 05:02:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/14/56092.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/56092.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/14/56092.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/56092.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/56092.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 前面一小节，我们已经写出了TcpServer的构造函数。这个函数的实际作用，就是创建了listen socket（监听嵌套字）。这一节，我们来具体分析这个创建的过程。<br><br>socket和sockaddr的创建是可以相互独立的<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在函数中，我们首先通过socket()系统调用创建了listenSock，然后通过为结构体赋值的方法具体定义了服务器端的sockaddr。（memset()函数的作用是把某个内存段的空间设定为某值，这里是清零。）其他的概念已经在前一小节讲完了。这里需要补充的是说明宏定义INADDR_ANY。这里的意思是使用本机所有可用的IP地址。当然，如果你机器绑定了多个IP地址，你也可以指定使用哪一个。<br><br>数据流简易模型（SOCK_STREAM）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们的例子以电话做的比喻，实际上，socket stream模型不完全类似电话，它至少有以下这些特点：<br>1、一种持续性的连接。这点跟电话是类似的，也可以想象成流动着液体的水管。一旦断开，这种流动就会中断。<br>2、数据包的发送实际上是非连续的。这个世界上有什么事物是真正的线性连续的？呵呵，扯远了，这貌似一个哲学问题。我们仅仅需要知道的是，一个数据包不可能是无限大的，所以，总是一个小数据包一个小数据包这样的发送的。这一点，又有点像邮包的传递。这些数据包到达与否，到达的先后次序本身是无法保证的，即是说，是IP协议无法保证的。但是stream形式的TCP协议，在IP之上，做了一定到达和到达顺序的保证。<br>3、传送管道实际上是非封闭的。要不干嘛叫&#8220;网络&#8221;-_-!!!。我们之所以能保证数据包的&#8220;定点&#8221;传送，完全是依靠每个数据包都自带了目的地址信息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由此可见，虽然socket和sockaddr可以分别创建，并无依赖关系。但是在实际使用的时候，一个socket至少会绑定一个本机的sockaddr，没有自己的&#8220;地址信息&#8221;，就不能接受到网络上的数据包（至少在TCP协议里面是这样的）。<br><br>socket与本机sockaddr的绑定<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有时候绑定是系统的任务，特别是当你不需要知道自己的IP地址和所使用的端口号的时候。但是，我们现在是建立服务器，你必须告诉客户端你的连接信息：IP和Port。所以，我们需要指明IP和Port，然后进行绑定。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bind(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;localAddress,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;addressLength);</span></div>
作为C++的程序员，也许你会觉得这个函数很不友好，它似乎更应该写成：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bind_cpp_style(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;sockaddr</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;localAddress);</span></div>
我们需要通过函数原型指明两点：<br>1、我们仅仅使用sockaddr结构的数据，但并不会对原有的数据进行修改；<br>2、我们使用的是完整的结构体，而不仅仅是这个结构体的指针。（很显然光用指针是无法说明结构体大小的）<br>幸运的是，在Linux的实现中，这个函数已经被写为：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Give&nbsp;the&nbsp;socket&nbsp;FD&nbsp;the&nbsp;local&nbsp;address&nbsp;ADDR&nbsp;(which&nbsp;is&nbsp;LEN&nbsp;bytes&nbsp;long).&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bind&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;__CONST_SOCKADDR_ARG&nbsp;__addr,&nbsp;socklen_t&nbsp;__len)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__THROW;</span></div>
看到亲切的const，我们就知道这个指针带入是没有&#8220;副作用&#8221;的。<br><br>监听：listen()<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream流模型形式上是一种&#8220;持续性&#8221;的连接，这就是要求信息的流动是&#8220;可来可去&#8221;的。也就是说，stream流的socket除了绑定本机的sockaddr，还应该拥有对方sockaddr的信息。在listen()中，这&#8220;对方的sockaddr&#8221;就可以不是某一个特定的sockaddr。实际上，listen socket的目的是准备被动的接受来自&#8220;所有&#8221;sockaddr的请求。所以，listen()反而就不能指定某个特定的sockaddr。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;queueLimit);</span></div>
其中第二个参数是等待队列的限制，一般设置在5-20。Linux中实现为：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Prepare&nbsp;to&nbsp;accept&nbsp;connections&nbsp;on&nbsp;socket&nbsp;FD.<br>&nbsp;&nbsp;&nbsp;N&nbsp;connection&nbsp;requests&nbsp;will&nbsp;be&nbsp;queued&nbsp;before&nbsp;further&nbsp;requests&nbsp;are&nbsp;refused.<br>&nbsp;&nbsp;&nbsp;Returns&nbsp;0&nbsp;on&nbsp;success,&nbsp;-1&nbsp;for&nbsp;errors.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__fd,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__n)&nbsp;__THROW;</span></div>
完成了这一步，回到我们的例子，就像是让你小弟在电话机前做好了接电话的准备工作。需要再次强调的是，这些行为仅仅是改变了socket的状态，实际上我想强调的是，为什么这些函数不会造成block（阻塞）的原因。（block的概念以后再解释）<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/56092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-14 13:02 <a href="http://www.cppblog.com/lf426/archive/2008/07/14/56092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：4、构造函数涉及的概念</title><link>http://www.cppblog.com/lf426/archive/2008/07/12/55956.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 12 Jul 2008 05:27:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/12/55956.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/55956.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/12/55956.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/55956.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/55956.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 话题回到&#8220;黑社会办公室&#8221;的例子，讲概念已经扯得比较远了，不过，这一节我们还得讲概念，不过好在有些程序的例子。如果大家不想翻回去看TcpServer类的原型，我这里直接给出这个头文件的完整源代码：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Filename:&nbsp;TcpServerClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef&nbsp;TCPSERVERCLASS_HPP_INCLUDED<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TCPSERVERCLASS_HPP_INCLUDED</span><span style="COLOR: #000000"><br><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TcpServer<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listenSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;communicationSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;servAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;clntAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;isAccept();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;handleEcho();<br>};<br><br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;TCPSERVERCLASS_HPP_INCLUDED</span></div>
我们已经解释了为什么listenSock和communicationSock的类型是int，以及sockaddr_in是什么结构，现在来写这个类的构造函数：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">TcpServer::TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listen_port)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;(listenSock&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;socket(PF_INET,&nbsp;SOCK_STREAM,&nbsp;IPPROTO_TCP))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">servAddr,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_family&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_addr.s_addr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;&nbsp;servAddr.sin_port&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;htons(listen_port);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;bind(listenSock,&nbsp;(sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">servAddr,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr))&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;listen(listenSock,&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen()&nbsp;failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
好，先看看程序培养一下感觉，我们还得说概念。<br><br>数据封装（Data Encapsutation）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们前面说到了网络分层：链路——网络——传输——应用。数据从应用程序里诞生，传送到互联网上每一层都会进行一次封装：<br>Data&gt;&gt;Application&gt;&gt;TCP/UDP&gt;&gt;IP&gt;&gt;OS(Driver, Kernel &amp; Physical Address)<br>我们用socket重点描述的是协议，包括网络协议（IP）和传输协议（TCP/UDP）。<br>sockaddr重点描述的是地址，包括IP地址和TCP/UDP端口。<br><br>socket()函数<br><br>&nbsp;&nbsp;&nbsp; 我们从TcpServer::TcpServer()函数可以看到，socket和sockaddr的产生是可以相互独立的。socket()的函数原型是：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;protocolFamily,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;type,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;protocol);</span></div>
在Linux中的实现为：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Create&nbsp;a&nbsp;new&nbsp;socket&nbsp;of&nbsp;type&nbsp;TYPE&nbsp;in&nbsp;domain&nbsp;DOMAIN,&nbsp;using<br>&nbsp;&nbsp;&nbsp;protocol&nbsp;PROTOCOL.&nbsp;&nbsp;If&nbsp;PROTOCOL&nbsp;is&nbsp;zero,&nbsp;one&nbsp;is&nbsp;chosen&nbsp;automatically.<br>&nbsp;&nbsp;&nbsp;Returns&nbsp;a&nbsp;file&nbsp;descriptor&nbsp;for&nbsp;the&nbsp;new&nbsp;socket,&nbsp;or&nbsp;-1&nbsp;for&nbsp;errors.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;socket&nbsp;(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__domain,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__type,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;__protocol)&nbsp;__THROW;</span></div>
第一个参数是协议簇（Linux里面叫作域，意思一样的），还是那句话，我们这篇教程用到的就仅仅是一个PF_INET（protocol family : internet），很多时候你会发现人们也经常在这里赋值为AF_INET，事实上，当前，AF_INET就是PF_INET的一个#define，但是，写成PF_INET从语义上会更加严谨。这也就是TCP/IP协议簇中的IP协议（Internet Protocol），网络层的协议。<br>后面两个参数定义传输层的协议。<br>第二个参数是传输层协议类型，我们教程里用到的宏，只有两个：SOCK_STREAM（数据流格式）和SOCK_DGRAM（数据报格式）；（具体是什么我们以后讨论）<br>第三个参数是具体的传输层协议。当赋值为0的时候，系统会根据传输层协议类型自动匹配和选择。事实上，当前，匹配SOCK_STREAM的就是TCP协议；而匹配SOCK_DGRAM就是UDP协议。所以，我们指定了第二个参数，第三个就可以简单的设置为0。不过，为了严谨，我们最好还是把具体协议写出来，比如，我们的例子中的TCP协议的宏名称：IPPROTO_TCP。<br><br>数据的&#8220;地址&#8221;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从数据封装的模型，我们可以看到数据是怎么从应用程序传递到互联网的。我们说过，数据的传送是通过socket进行的。但是socket只描述了协议类型。要让数据正确的传送到某个地方，必须添加那个地方的sockaddr地址；同样，要能接受网络上的数据，必须有自己的sockaddr地址。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可见，在网络上传送的数据包，是socket和sockaddr共同&#8220;染指&#8221;的结果。他们共同封装和指定了一个数据包的网络协议（IP）和IP地址，传输协议（TCP/UDP）和端口号。<br><br>网络字节和本机字节的相互转换<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sockaddr结构中的IP地址（sin_addr.s_addr）和端口号（sin_port）将被封装到网络上传送的数据包中，所以，它的结构形式需要保证是网络字节形式。我们这里用到的函数是htons()和htonl()，这些缩写的意思是：<br>h: host，主机（本机）<br>n: network，网络<br>to: to转换<br>s: short，16位（2字节，常用于端口号）<br>l: long, 32位（4字节，常用于IP地址）<br>&#8220;反过来&#8221;的函数也是存在的ntohs()和ntohl()。<br><br>动作与持续行为<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本节最后的一个概念可以跟计算机无关。作为动词，有些可以描述动作，有些是描述一重持续的行为状态的（就如同一般动词和be动词一样）。扯到C++来说，我们可以把持续行为封装到函数内部，只留出动作的接口。事实上，构造函数中的bind()和listen()就是这种描述持续状态的行为函数。<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/55956.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-12 13:27 <a href="http://www.cppblog.com/lf426/archive/2008/07/12/55956.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：3、sockaddr与sockaddr_in</title><link>http://www.cppblog.com/lf426/archive/2008/07/10/55800.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 10 Jul 2008 07:14:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/10/55800.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/55800.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/10/55800.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/55800.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/55800.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>收件人地址<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一家化妆品公司将一批新产品的样品，准备发给某学校某个班的女生们免费试用。通常情况下，这件邮包的地址上可以这么写：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">收件人：全体女生。<br>地址：A省B市C学校，X级Y班。</span></div>
但是，如果在描述地址的时候这样写呢：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">收件人：全体女生。<br>地址：请打电话xxxxxxxx，找他们学校一个叫Lucy的女生，然后把东西送到她的班上。</span></div>
这种文字是相当的诡异啊-_-!!!，但是并不等于就没有表述清楚邮包的去向和地址。事实上邮局看到这样的地址一定会发飙的，然而对于电脑，如果你的地址描述形式是他可以接受和执行的，他就会老老实实的按你的要求去做&#8230;&#8230;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以，如何描述地址不是问题的关键，关键在于这样的表述是不是能够表述清楚一个地址。一种更加通用的表达形式可能是这样的：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">收件人：全体女生。<br>地址：</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">一种地址描述方式</span><span style="COLOR: #000000">&gt;</span></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 事实上，在socket的通用address描述结构sockaddr中正是用这样的方式来进行地址描述的：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;sa_family;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;sa_data[</span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">];<br>};</span></div>
这是一个16字节大小的结构（2+14），sa_family可以认为是socket address family的缩写，也可能被简写成AF（Address Family），他就好像我们例子中那个&#8220;收件人：全体女生&#8221;一样，虽然事实上有很多AF的种类，但是我们这个教程中只用得上大名鼎鼎的internet家族AF_INET。另外的14字节是用来描述地址的。这是一种通用结构，事实上，当我们指定sa_family=AF_INET之后，sa_data的形式也就被固定了下来：最前端的2字节用于记录16位的端口，紧接着的4字节用于记录32位的IP地址，最后的8字节清空为零。这就是我们实际在构造sockaddr时候用到的结构sockaddr_in（意指socket address internet）：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr_in<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;sin_family;<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;sin_port;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr&nbsp;sin_addr;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;sin_zero[</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">];<br>};</span></div>
我想，sin_的意思，就是socket (address) internet吧，只不过把address省略掉了。sin_addr被定义成了一个结构，这个结构实际上就是：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000">&nbsp;s_addr;<br>};</span></div>
in_addr显然是internet address了，s_addr是什么意思呢？说实话我没猜出值得肯定的答案（根据下面网友的评论，其意思为source address，谢谢），也许就是socket address的意思吧，尽管跟更广义的sockaddr结构意思有所重复了。哎，这些都是历史原因，也许我是没有精力去考究了。<br><br>sockaddr和sockaddr_in在Linux中的实现<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可能还记得我之前说过，UNIX和Linux上的socket实现都是从BSD的socket实现演变过来的。事实上，socket这个词本来的意思，就是<span style="FONT-STYLE: italic">Berkeley Socket interface</span>的简单说法。Linux上的socket与原本的socket的应该是完全兼容的，不过发展到今天，在代码实现上可能有些小的差别。我们就吹毛求疵的来看看这些区别在什么地方。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">bits</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Structure&nbsp;describing&nbsp;a&nbsp;generic&nbsp;socket&nbsp;address.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;__SOCKADDR_COMMON&nbsp;(sa_);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Common&nbsp;data:&nbsp;address&nbsp;family&nbsp;and&nbsp;length.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;sa_data[</span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Address&nbsp;data.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;};<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">==============<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;POSIX.1g&nbsp;specifies&nbsp;this&nbsp;type&nbsp;name&nbsp;for&nbsp;the&nbsp;`sa_family'&nbsp;member.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>typedef&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sa_family_t;<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;This&nbsp;macro&nbsp;is&nbsp;used&nbsp;to&nbsp;declare&nbsp;the&nbsp;initial&nbsp;common&nbsp;members<br>&nbsp;&nbsp;&nbsp;of&nbsp;the&nbsp;data&nbsp;types&nbsp;used&nbsp;for&nbsp;socket&nbsp;addresses,&nbsp;`struct&nbsp;sockaddr',<br>&nbsp;&nbsp;&nbsp;`struct&nbsp;sockaddr_in',&nbsp;`struct&nbsp;sockaddr_un',&nbsp;etc.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;__SOCKADDR_COMMON(sa_prefix)&nbsp;\</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;sa_family_t&nbsp;sa_prefix##family<br><br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;__SOCKADDR_COMMON_SIZE&nbsp;&nbsp;&nbsp;&nbsp;(sizeof&nbsp;(unsigned&nbsp;short&nbsp;int))</span></div>
可以看到，转了几次typedef，几次宏定义，实际效果是与标准socket一样的。<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">netinet</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Internet&nbsp;address.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>typedef&nbsp;uint32_t&nbsp;in_addr_t;<br></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;in_addr_t&nbsp;s_addr;<br>&nbsp;&nbsp;};<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">=================</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Structure&nbsp;describing&nbsp;an&nbsp;Internet&nbsp;socket&nbsp;address.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr_in<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;__SOCKADDR_COMMON&nbsp;(sin_);<br>&nbsp;&nbsp;&nbsp;&nbsp;in_port_t&nbsp;sin_port;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Port&nbsp;number.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr&nbsp;sin_addr;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Internet&nbsp;address.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Pad&nbsp;to&nbsp;size&nbsp;of&nbsp;`struct&nbsp;sockaddr'.&nbsp;&nbsp;</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;sin_zero[</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;sockaddr)&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__SOCKADDR_COMMON_SIZE&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">&nbsp;(in_port_t)&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;in_addr)];<br>&nbsp;&nbsp;};</span></div>
同样的，看起来挺复杂，实际上与标准socket的定义是一样的。<br><br>头文件依赖关系<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;bits/socket.h&gt;是包含在&lt;sys/socket.h&gt;中的，&lt;netinet/in.h&gt;是包含在&lt;arpa/inet.h&gt;中的，实际上我们在程序中往往就是：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span></div>
值得知道的是，ARPA是 Advanced research project agency（美国国防部高级研究计划暑）的所写，ARPANET是当今互联网的前身，所以我们就可以想象，为什么inet.h会在arpa目录下了。<br>
<img src ="http://www.cppblog.com/lf426/aggbug/55800.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-10 15:14 <a href="http://www.cppblog.com/lf426/archive/2008/07/10/55800.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：2、socket与文件描述符</title><link>http://www.cppblog.com/lf426/archive/2008/07/10/55771.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Wed, 09 Jul 2008 18:42:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/10/55771.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/55771.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/10/55771.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/55771.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/55771.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>UNIX中的一切事物都是文件（<em>everything</em> in Unix is a file!）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我在这篇教程中提到UNIX的时候，其意思专指符合UNIX标准的所谓&#8220;正统&#8221;UNIX的衍生系统（其实我就用来带指那些买了最初UNIX源代码的商业系统）操作系统和类似Linux，BSD这些类UNIX系统。如果某些要点是Linux特有的，或者因为本人孤陋寡闻暂时搞不清楚是Linux特有的还是UNIX通用的，我就会指明是Linux，甚至其发行版（我本人在写这篇教程的时候是以Debian GNU/Linux 4.0 etch为测试平台的）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们学习UNIX的时候，恐怕听到的第一句话就是这句：UNIX中一切都是文件。这是UNIX的基本理念之一，也是一句很好的概括。比如，很多UNIX老鸟会举出个例子来，&#8220;你看，/dev/hdc是个文件，它实际上也是我的光盘&#8230;&#8230;&#8221;UNIX中的文件可以是：网络连接（network connection），输入输出（FIFO），管道（a pipe），终端（terminal），硬盘上的实际文件，或者其它任何东东。<br><br>文件与文件描述符（file &amp; file descriptor）<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可能对上一章中建模类中的int还记忆犹新。我们用int在描述socket，实际上，所有的文件描述符都是int，没错，用的是一个整数类型。如果你觉得这样让你很难接受，那么恭喜你，你跟我一样，也许是深中C++面向对象思想的毒了^^。因为是int，所以文件描述符不可能是C++概念中的对象，因为int无法发出行为，但是，这并不代表也不能接受一个动作哈。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PASCAL之父在批判面向对象思想教条的时候，曾经生动的举了个例子，&#8220;在OOP的概念中，绝对不应该接受a+b这种表达的， OOP对这个问题的表达应该是a.add(b)&#8221;。fd（file descriptor）可以作为接受动作的对象，但是本身却无法发出动作，这就如同一个只能做宾语不能做主语的名词，是个不完整的对象。但是，请别忘了Linux和socket本身是C语言的产物，我们必须接受在面向过程时代下的产物，正视历史——当然，这与我们自己再进行OOP的封装并不矛盾。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们应该记住3个已经打开的fd，0：标准输入（STDIN_FILENO）；1：标准输出（STDOUT_FILENO）；2：标准错误（STDERR_FILENO）。（以上宏定义在&lt;unistd.h&gt;中）一个最简单的使用fd的例子，就是使用&lt;unistd.h&gt;中的函数：write(1, "Hello, World!\n", 20);，在标准输出上显示&#8220;Hello, World!&#8221;。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外一个需要注意的问题是，file和fd并非一定是一一对应的。当一个file被多个程序调用的时候，会生成相互独立的fd。这个概念可以类比于C++中的引用（eg: int&amp; rTmp = tmp;）。<br><br>socket与file descriptor<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文件是应用程序与系统（包括特定硬件设备）之间的桥梁，而文件描述符就是应用程序使用这个&#8220;桥梁&#8221;的接口。在需要的时候，应用程序会向系统申请一个文件，然后将文件的描述符返回供程序使用。返回socket的文件通常被创建在/tmp或者/usr/tmp中。我们实际上不用关心这些文件，仅仅能够利用返回的socket描述符就可以了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好了，说了这么多，实际上就解释了一个问题，&#8220;为什么socket的类型是int？&#8221; -_-!!!<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/55771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-10 02:42 <a href="http://www.cppblog.com/lf426/archive/2008/07/10/55771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket 编程入门教程（一）TCP server 端：1、建模</title><link>http://www.cppblog.com/lf426/archive/2008/07/08/55641.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Tue, 08 Jul 2008 07:42:00 GMT</pubDate><guid>http://www.cppblog.com/lf426/archive/2008/07/08/55641.html</guid><wfw:comment>http://www.cppblog.com/lf426/comments/55641.html</wfw:comment><comments>http://www.cppblog.com/lf426/archive/2008/07/08/55641.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/lf426/comments/commentRss/55641.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lf426/services/trackbacks/55641.html</trackback:ping><description><![CDATA[作者：龙飞<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 绝大部分关于socket编程的教程总是从socket的概念开始讲起的。要知道，socket的初衷是个庞大的体系，TCP/IP只是这个庞大体系下一个很小的子集，而我们真正能用上的更是这个子集中的一小部分：运输层（Host-to-Host Transport Layer）的TCP和UDP协议，以及使用这两个协议进行应用层（Application Layer）的开发。即使是socket的核心部分，网络层（Internet Layer）的IP协议，在编程的时候我们也很少会感觉到它的存在——因为已经被封装好了，我们唯一需要做的事情就是传入一个宏。第一节我想介绍的概念就这么多，当然，既然我们已经说了3个层了，我想最好还是把最后一个层也说出来，即所谓链路层（Network Access Layer），它包括了物理硬件和驱动程序。这四个层从底到高的顺序是：链路层－－网络层－－运输层－－应用层。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好，说实话我们现在并不清楚所谓TCP到底是什么东东，不过我们知道这东东名气很大。或许你早就知道，另外一个声名狼藉建立在TCP协议基础上的应用程序，它曾经几乎是统治了一个时代，即使是今天，我们依然无法消除他的影响力的——恩，是的，就是telnet。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个教程中，我使用的环境是Debian GNU/Linux 4.0 etch。传说中的stable -_-!!!，恩，我是很保守的人。如果你不是自己DIY出来的系统，相信默认安装里面就应该有telnet（/usr/bin/telnet，要是没装就自己aptitude install吧）。telnet可以与所有遵循TCP协议的服务器端进行通讯。通常，socket编程总是Client/Server形式的，因为有了telnet，我们可以先不考虑client的程序，我们先写一个支持TCP协议的server端，然后用telnet作为client验证我们的程序就好了。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server端的功能，我们也考虑一种最简单的反馈形式：echo。就如同你在终端输入echo 'Hello World'，回车后shell就会给你返回Hello World一样，我们的第一个TCP server就用以实现这个功能。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 什么样的模型适合描述这样的一种server呢？我相信，一个很2的例子会有助于我们记忆TCP server端的基本流程。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 想象你自己是个小大佬，坐办公室（什么样的黑社会做办公室啊？可能是讨债公司吧^^）你很土，只有一个小弟帮你接电话（因为你自己的号码是不敢对外公开的）。一次通讯的流程大概应该是这样的：小弟那里的总机电话响了；小弟接起电话；对方说是你女朋友A妹；小弟转达说，&#8220;老大，你马子电话&#8221;；你说，接过来；小弟把电话接给你；你和你女朋友聊天半小时；挂电话。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们来分析一下整个过程中的元素。先分析成员数据（请注意，这里开始用C++术语了）：你小弟（listenSock），你需要他来监听（listen，这是socket编程中的术语）电话；你自己（communicationSock），实际上打电话进行交流的是你自己；你的电话号码（servAddr），否则你女朋友怎么能找到你？你女朋友的电话号码（clntAddr），这个比喻有点牵强，因为事实上你接起电话，不需要知道对方的号码也可以通话（虽然事实上你应该是知道的，你不会取消了来电显示功能吧^^），但是，难道你是只接女朋友电话从来不打过去的牛人吗？这个过程中的行为（成员函数）：你小弟接电话并转接给你（isAccept()）；你自己的通话（handleEcho()）（这个行为确实比较土，只会乌鸦学舌的echo，呵呵）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 简单的说，就是这些了。根据这个模型，我们可以很容易写出实现我们需要的echo功能的TCP server的类：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;TcpServer<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;listenSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;communicationSock;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;servAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;sockaddr_in&nbsp;clntAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>&nbsp;&nbsp;&nbsp;&nbsp;TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> listen_port);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;isAccept();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;handleEcho();<br>};</span></div>
这里面有些简写，比如，sock实际上就是socket，addr就是address。serv和clnt我想你一定能猜到是server和client吧。还有一个socket中的结构体sockaddr_in，实际上就是这个意思：socket address internet（网络嵌套字地址），具体解说，请看下回分解。<br><br>
<img src ="http://www.cppblog.com/lf426/aggbug/55641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lf426/" target="_blank">lf426</a> 2008-07-08 15:42 <a href="http://www.cppblog.com/lf426/archive/2008/07/08/55641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>