﻿<?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++博客-aurain-随笔分类-socket编程</title><link>http://www.cppblog.com/aurain/category/6202.html</link><description>专注Windows下的驱动开发、网络开发</description><language>zh-cn</language><lastBuildDate>Thu, 13 Mar 2014 18:03:39 GMT</lastBuildDate><pubDate>Thu, 13 Mar 2014 18:03:39 GMT</pubDate><ttl>60</ttl><item><title>TCP连接关闭状态转换图</title><link>http://www.cppblog.com/aurain/archive/2014/03/13/206149.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Thu, 13 Mar 2014 05:22:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2014/03/13/206149.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/206149.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2014/03/13/206149.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/206149.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/206149.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: tcp连接断开状态转换图&nbsp;&nbsp;<a href='http://www.cppblog.com/aurain/archive/2014/03/13/206149.html'>阅读全文</a><img src ="http://www.cppblog.com/aurain/aggbug/206149.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2014-03-13 13:22 <a href="http://www.cppblog.com/aurain/archive/2014/03/13/206149.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>讨论:关于客户端使用何种网络模型</title><link>http://www.cppblog.com/aurain/archive/2008/10/10/63666.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Fri, 10 Oct 2008 08:34:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/10/10/63666.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/63666.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/10/10/63666.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/63666.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/63666.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Windows网络应用中，对于服务端我们一般会选择Windows提供的IO模型，如完成端口模型IOCP。<br>对于客户端需要主动连接多个不同IP的TCP的情况（10或更多），那么使用什么模型比较好呢？&nbsp;&nbsp;<a href='http://www.cppblog.com/aurain/archive/2008/10/10/63666.html'>阅读全文</a><img src ="http://www.cppblog.com/aurain/aggbug/63666.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-10-10 16:34 <a href="http://www.cppblog.com/aurain/archive/2008/10/10/63666.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Winsock的两种I/O模式</title><link>http://www.cppblog.com/aurain/archive/2008/02/26/43262.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Tue, 26 Feb 2008 07:39:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/02/26/43262.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/43262.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/02/26/43262.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/43262.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/43262.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">阻塞模式：执行</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">I/O</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">操作完成前会一直进行等待，不会将控制权交给程序。套接字</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">默认为阻塞模式。可以通过多线程技术进行处理。</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> <br></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">非阻塞模式：执行</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">I/O</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">操作时，</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Winsock</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">函数会返回并交出控制权。这种模式使用</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> </span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">起来比较复杂，因为函数在没有运行完成就进行返回，会不断地返回</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体"> WSAEWOULDBLOCK</span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: Tahoma; mso-hansi-font-family: Tahoma; mso-bidi-font-family: Tahoma; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">错误。但功能强大。</span>
<img src ="http://www.cppblog.com/aurain/aggbug/43262.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-02-26 15:39 <a href="http://www.cppblog.com/aurain/archive/2008/02/26/43262.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络编程基础</title><link>http://www.cppblog.com/aurain/archive/2008/02/25/43202.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Mon, 25 Feb 2008 05:40:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/02/25/43202.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/43202.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/02/25/43202.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/43202.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/43202.html</trackback:ping><description><![CDATA[Socket 编程最基本的模型就是 <font size=2>Berkeley Socket</font>
<p><img src="http://www.yesky.com/image20010518/54933.GIF" align=absMiddle></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 具体的实现也就是按这个流程图来做的，这里重点是服务端的实现。</p>
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: rgb(230,230,230) 0% 50%; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">
<div><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> APIENTRY _tWinMain(HINSTANCE hInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINSTANCE hPrevInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPTSTR&nbsp;&nbsp;&nbsp;&nbsp; lpCmdLine,<br>&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: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nCmdShow)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ofstream logfile(</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">LogFile.txt</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)">Initialize winsock</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WSADATA wsaData;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> iResult </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> WSAStartup( MAKEWORD(</span><span style="COLOR: rgb(0,0,0)">2</span><span style="COLOR: rgb(0,0,0)">,</span><span style="COLOR: rgb(0,0,0)">2</span><span style="COLOR: rgb(0,0,0)">), </span><span style="COLOR: rgb(0,0,0)">&amp;</span><span style="COLOR: rgb(0,0,0)">wsaData);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)">(iResult </span><span style="COLOR: rgb(0,0,0)">!=</span><span style="COLOR: rgb(0,0,0)"> NO_ERROR)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Error at WSAStartup() </span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile.close();<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: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">1</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">else</span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Initialize WSAStartup OK!</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)"> Create a socket.</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOCKET serverSocket;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; serverSocket </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)">(serverSocket </span><span style="COLOR: rgb(0,0,0)">==</span><span style="COLOR: rgb(0,0,0)"> INVALID_SOCKET) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Error at socket():</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">WSAGetLastError()</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">endl;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WSACleanup();<br>&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: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">1</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">else</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Create socket OK!</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)"> Bind the socket.</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sockaddr_in service;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; service.sin_family</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; service.sin_addr.s_addr</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">inet_addr(HostIp.c_str());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; service.sin_port</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">htons(PORT);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)"> (bind(serverSocket,(SOCKADDR</span><span style="COLOR: rgb(0,0,0)">*</span><span style="COLOR: rgb(0,0,0)">)</span><span style="COLOR: rgb(0,0,0)">&amp;</span><span style="COLOR: rgb(0,0,0)">service,</span><span style="COLOR: rgb(0,0,255)">sizeof</span><span style="COLOR: rgb(0,0,0)">(service))</span><span style="COLOR: rgb(0,0,0)">==</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">bind() failed</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">GetLastError()</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; closesocket(serverSocket);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile.close();<br>&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: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">1</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">else</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Binding OK!</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)"> Listen on the socket.</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)">(listen(serverSocket,</span><span style="COLOR: rgb(0,0,0)">1</span><span style="COLOR: rgb(0,0,0)">)</span><span style="COLOR: rgb(0,0,0)">==</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Error listening on socket</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">GetLastError()</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile.close();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">else</span><span style="COLOR: rgb(0,0,0)"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logfile</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Listening...</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">endl;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)"> Accept connections.</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SOCKET clientSocket;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sockaddr_in clientAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> clientAddrLen</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,255)">sizeof</span><span style="COLOR: rgb(0,0,0)">(clientAddr);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">while</span><span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(0,0,255)">true</span><span style="COLOR: rgb(0,0,0)">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<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; clientSocket </span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)"> SOCKET_ERROR;<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: rgb(0,0,255)">while</span><span style="COLOR: rgb(0,0,0)">(clientSocket</span><span style="COLOR: rgb(0,0,0)">==</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR) <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; {<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; clientSocket</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">accept(serverSocket,(</span><span style="COLOR: rgb(0,0,255)">struct</span><span style="COLOR: rgb(0,0,0)"> sockaddr</span><span style="COLOR: rgb(0,0,0)">*</span><span style="COLOR: rgb(0,0,0)">)</span><span style="COLOR: rgb(0,0,0)">&amp;</span><span style="COLOR: rgb(0,0,0)">clientAddr,</span><span style="COLOR: rgb(0,0,0)">&amp;</span><span style="COLOR: rgb(0,0,0)">clientAddrLen);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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; }<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; ReceiveData(clientSocket);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; closesocket(serverSocket);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; closesocket(clientSocket); <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">return</span><span style="COLOR: rgb(0,0,0)"> </span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">;<br>}<br><br></span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)">Receive the data</span><span style="COLOR: rgb(0,128,0)"><br></span><span style="COLOR: rgb(0,0,255)">void</span><span style="COLOR: rgb(0,0,0)"> ReceiveData(SOCKET</span><span style="COLOR: rgb(0,0,0)">&amp;</span><span style="COLOR: rgb(0,0,0)"> clientSocket)<br>{&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> bytesSent;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)"> bytesRecv</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">string</span><span style="COLOR: rgb(0,0,0)"> sendbuf</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">""</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">char</span><span style="COLOR: rgb(0,0,0)"> recvbuf[</span><span style="COLOR: rgb(0,0,0)">32</span><span style="COLOR: rgb(0,0,0)">]</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">""</span><span style="COLOR: rgb(0,0,0)">;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">while</span><span style="COLOR: rgb(0,0,0)">(bytesRecv </span><span style="COLOR: rgb(0,0,0)">==</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesRecv</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">recv(clientSocket,recvbuf,</span><span style="COLOR: rgb(0,0,0)">32</span><span style="COLOR: rgb(0,0,0)">,</span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendbuf</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">Received: </span><span style="COLOR: rgb(0,0,0)">"</span><span style="COLOR: rgb(0,0,0)">+</span><span style="COLOR: rgb(0,0,0)">(</span><span style="COLOR: rgb(0,0,255)">string</span><span style="COLOR: rgb(0,0,0)">)recvbuf;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesSent</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">send(clientSocket,sendbuf.c_str(),(unsigned </span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">)(sendbuf.size()),</span><span style="COLOR: rgb(0,0,0)">0</span><span style="COLOR: rgb(0,0,0)">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytesRecv</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">SOCKET_ERROR;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(recvbuf,</span><span style="COLOR: rgb(0,0,0)">'\0',32);</span></div>
<div><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;</span></div>
<div><span style="COLOR: rgb(0,0,0)">}</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在接收客户端发来数据的地方要做成死循环，如果需要断开连接，则由客户断发送特定的消息然后进行处理。还有需要注意的是上面的HostIp是本机的IP地址，PORT是套接字需要绑定的端口。</p>
<img src ="http://www.cppblog.com/aurain/aggbug/43202.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-02-25 13:40 <a href="http://www.cppblog.com/aurain/archive/2008/02/25/43202.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在vc中通过连接池操作mysql(api方式)，附c++访问mysql的封装类</title><link>http://www.cppblog.com/aurain/archive/2008/02/21/43049.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Thu, 21 Feb 2008 07:10:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/02/21/43049.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/43049.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/02/21/43049.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/43049.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/43049.html</trackback:ping><description><![CDATA[<p>在有大量节点访问的数据库设计中,经常要使用到连接池来管理所有的连接.<br>一般方法是:建立两个连接句柄队列,空闲的等待使用的队列和正在使用的队列.<br>当要查询时先从空闲队列中获取一个句柄,插入到正在使用的队列,再用这个句柄做数据库操作,完毕后一定要从使用队列中删除,再插入到空闲队列.<br>代码如下：<br>MySQLMan.h<br>&nbsp;// MySQLMan.h: interface for the CMySQLMan class.<br>//<br>//////////////////////////////////////////////////////////////////////<br>#include &lt;mysql.h&gt;<br>#pragma comment(lib,"libmySQL.lib")</p>
<p>#include &lt;list&gt;</p>
<p>typedef std::list&lt;MYSQL *&gt; CONNECTION_HANDLE_LIST;<br>typedef std::list&lt;MYSQL *&gt;::iterator ITER_CONNECTION_HANDLE_LIST;</p>
<p>#define CONNECTION_NUM&nbsp;10&nbsp;//同时打开的连接数</p>
<p>class CMySQLMan&nbsp; <br>{<br>public:<br>&nbsp;CMySQLMan();<br>&nbsp;CMySQLMan(const char *host, const char *user, const char *password, const char *db, unsigned int port=3306);<br>&nbsp;virtual ~CMySQLMan();<br>&nbsp;<br>public:<br>&nbsp;bool ConnectDB();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//连接数据库<br>&nbsp;MYSQL_RES* SelectRecord(const char *szSql);&nbsp;//选择记录，返回结果集<br>&nbsp;bool SelectDB(const char *szDB);&nbsp;&nbsp;//选择数据库<br>&nbsp;bool UpdateRecord(const char *szSql);&nbsp;//更新记录<br>&nbsp;bool InsertRecord(const char *szSql);&nbsp;//插入记录<br>&nbsp;bool DelRecord(const char *szSql);&nbsp;&nbsp;//删除记录</p>
<p>&nbsp;BOOL IsEnd(MYSQL_RES *myquery);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//是否最后<br>&nbsp;void SeekData(MYSQL_RES *myquery, int offset);&nbsp;&nbsp;&nbsp;&nbsp;//查找指定数据<br>&nbsp;void FreeRecord(MYSQL_RES *myquery);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//释放结果集<br>&nbsp;unsigned int GetFieldNum(MYSQL_RES *myquery);&nbsp;&nbsp;&nbsp;&nbsp;//得到字段数<br>&nbsp;MYSQL_ROW GetRecord(MYSQL_RES *myquery);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//得到结果（一个记录）<br>&nbsp;my_ulonglong GetRowNum(MYSQL_RES *myquery);&nbsp;&nbsp;&nbsp;&nbsp;//得到记录数<br>&nbsp;char* OutErrors(MYSQL* pMySql);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//输出错误信息</p>
<p>&nbsp;char* GetState();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//服务器状态<br>&nbsp;char* GetServerInfo();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//服务器信息<br>&nbsp;int GetProtocolInfo();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//协议信息<br>&nbsp;char* GetHostInfo();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//主机信息<br>&nbsp;char* GetClientInfo();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//客户机信息<br>&nbsp;char* GetFieldName(MYSQL_RES *myquery, int FieldNum);&nbsp;&nbsp;//字段名</p>
<p>&nbsp;bool LockTable(const char *TableName, const char *Priority);&nbsp;//对特定表加锁<br>&nbsp;bool UnlockTable();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//解锁<br>&nbsp;bool SetCharset();<br>&nbsp;//int CreateDB(char *db);&nbsp;&nbsp;&nbsp;&nbsp;//创建数据库，返回错误信息<br>&nbsp;//int DropDB(char *db);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//删除数据库,返回错误信息</p>
<p>&nbsp;MYSQL* GetIdleMySql();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//提取一个空闲句柄供使用<br>&nbsp;void SetIdleMysql(MYSQL* pMySql);&nbsp;&nbsp;//从使用队列中释放一个使用完毕的句柄，插入到空闲队列</p>
<p>public:<br>&nbsp;//MYSQL&nbsp;&nbsp;m_mysql;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//数据库连接句柄<br>&nbsp;MYSQL_ROW&nbsp;m_row;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//记录集(单行)<br>&nbsp;MYSQL_FIELD *m_field;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//字段信息（结构体）</p>
<p>&nbsp;//创建两个队列<br>&nbsp;CONNECTION_HANDLE_LIST m_lsBusyList;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //正在使用的连接句柄<br>&nbsp;CONNECTION_HANDLE_LIST m_lsIdleList;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //未使用的连接句柄</p>
<p>&nbsp;CRITICAL_SECTION&nbsp;m_csList;</p>
<p>public:<br>&nbsp;char m_host[20];&nbsp;&nbsp;&nbsp;//主机<br>&nbsp;char m_user[20];&nbsp;&nbsp;&nbsp;//用户名<br>&nbsp;char m_password[20];&nbsp;&nbsp;//密码<br>&nbsp;char m_db[20];&nbsp;&nbsp;&nbsp;&nbsp;//数据库名<br>&nbsp;unsigned int m_port;&nbsp;&nbsp;//端口<br>};<br><br>MySQLMan.cpp<br>// MySQLMan.cpp: implementation of the MySQLMan class.<br>//<br>//////////////////////////////////////////////////////////////////////<br>#include "StdAfx.h"<br>#include "MySQLMan.h"</p>
<p>//////////////////////////////////////////////////////////////////////<br>// Construction/Destruction<br>//////////////////////////////////////////////////////////////////////</p>
<p>CMySQLMan::CMySQLMan()<br>{<br>&nbsp;<br>}</p>
<p>CMySQLMan::CMySQLMan(const char *host, const char *user, const char *password, const char *db, unsigned int port/* =3306 */)<br>{<br>&nbsp;strcpy(m_host, host);<br>&nbsp;strcpy(m_user, user);<br>&nbsp;strcpy(m_password, password);<br>&nbsp;strcpy(m_db, db);<br>&nbsp;m_port = port;</p>
<p>&nbsp;InitializeCriticalSection(&amp;m_csList);<br>}</p>
<p>CMySQLMan::~CMySQLMan()<br>{<br>&nbsp;for (ITER_CONNECTION_HANDLE_LIST iter=m_lsBusyList.begin(); iter != m_lsBusyList.end(); iter++)<br>&nbsp;{<br>&nbsp;&nbsp;mysql_close((*iter));<br>&nbsp;}</p>
<p>&nbsp;for (ITER_CONNECTION_HANDLE_LIST iter=m_lsIdleList.begin(); iter != m_lsIdleList.end(); iter++)<br>&nbsp;{<br>&nbsp;&nbsp;mysql_close((*iter));<br>&nbsp;}</p>
<p>&nbsp;DeleteCriticalSection(&amp;m_csList);<br>}</p>
<p>bool CMySQLMan::ConnectDB()<br>{<br>&nbsp;//同时打开CONNECTION_NUM个连接<br>&nbsp;try<br>&nbsp;{<br>&nbsp;&nbsp;for (int i=0; i&lt;CONNECTION_NUM; ++i)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;MYSQL *pMySql = mysql_init((MYSQL*)NULL);<br>&nbsp;&nbsp;&nbsp;if (pMySql != NULL)<br>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;if (!mysql_real_connect(pMySql,m_host,m_user,m_password,m_db,m_port,NULL,0))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutErrors(pMySql);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;m_lsIdleList.push_back(pMySql);<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;catch (...)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;return true;<br>}</p>
<p>MYSQL* CMySQLMan::GetIdleMySql()<br>{<br>&nbsp;MYSQL* pMySql = NULL;<br>&nbsp;EnterCriticalSection(&amp;m_csList);<br>&nbsp;if (m_lsIdleList.size() &gt; 0)<br>&nbsp;{<br>&nbsp;&nbsp;pMySql = m_lsIdleList.front();<br>&nbsp;&nbsp;m_lsIdleList.pop_front();<br>&nbsp;&nbsp;m_lsBusyList.push_back(pMySql);<br>&nbsp;}<br>&nbsp;else<br>&nbsp;{<br>&nbsp;&nbsp;pMySql = NULL;<br>&nbsp;}<br>&nbsp;LeaveCriticalSection(&amp;m_csList);</p>
<p>&nbsp;return pMySql;<br>}</p>
<p>void CMySQLMan::SetIdleMysql(MYSQL* pMySql)<br>{<br>&nbsp;EnterCriticalSection(&amp;m_csList);<br>&nbsp;m_lsBusyList.remove(pMySql);<br>&nbsp;m_lsIdleList.push_back(pMySql);<br>&nbsp;LeaveCriticalSection(&amp;m_csList);<br>}</p>
<p>MYSQL_RES* CMySQLMan::SelectRecord(const char *szSql)<br>{<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}<br>&nbsp;if(mysql_query(pMySql,szSql))<br>&nbsp;&nbsp;return NULL;<br>&nbsp;MYSQL_RES *myquery = NULL;<br>&nbsp;myquery = mysql_store_result(pMySql);<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return myquery;<br>}</p>
<p>bool CMySQLMan::InsertRecord(const char *szSql)<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if(mysql_query(pMySql,szSql))<br>&nbsp;{<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;}<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>bool CMySQLMan::UpdateRecord(const char *szSql)<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if(mysql_query(pMySql,szSql))<br>&nbsp;{<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;}<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>bool CMySQLMan::DelRecord(const char *szSql)<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if(mysql_query(pMySql,szSql))<br>&nbsp;{<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;}<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>bool CMySQLMan::SelectDB(const char *szDB)<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if (mysql_select_db(pMySql,szDB))<br>&nbsp;&nbsp;bRet = false;&nbsp;<br>&nbsp;else<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>my_ulonglong CMySQLMan::GetRowNum(MYSQL_RES *myquery)<br>{<br>&nbsp;return mysql_num_rows(myquery);<br>}</p>
<p>MYSQL_ROW CMySQLMan::GetRecord(MYSQL_RES *myquery)<br>{<br>&nbsp;m_row = mysql_fetch_row(myquery);</p>
<p>&nbsp;return m_row;<br>}</p>
<p>unsigned int CMySQLMan::GetFieldNum(MYSQL_RES *myquery)<br>{<br>&nbsp;return mysql_num_fields(myquery);<br>}</p>
<p>void CMySQLMan::FreeRecord(MYSQL_RES *myquery)<br>{<br>&nbsp;mysql_free_result(myquery);<br>}</p>
<p>//int CMySQLMan::CreateDB(char *db)<br>//{<br>//&nbsp;return mysql_create_db(&amp;m_mysql,db);<br>//}</p>
<p>void CMySQLMan::SeekData(MYSQL_RES *myquery, int offset)<br>{<br>&nbsp;mysql_data_seek(myquery,offset);<br>}</p>
<p><br>char * CMySQLMan::OutErrors(MYSQL *pMySql)<br>{<br>&nbsp;return const_cast&lt;char *&gt;(mysql_error(pMySql));<br>}</p>
<p>BOOL CMySQLMan::IsEnd(MYSQL_RES *myquery)<br>{<br>&nbsp;return mysql_eof(myquery);<br>}</p>
<p>char* CMySQLMan::GetFieldName(MYSQL_RES *myquery, int FieldNum)<br>{<br>&nbsp;m_field = mysql_fetch_field_direct(myquery, FieldNum);</p>
<p>&nbsp;return m_field-&gt;name;<br>}</p>
<p>char * CMySQLMan::GetClientInfo()<br>{<br>&nbsp;return const_cast&lt;char *&gt;(mysql_get_client_info());<br>}</p>
<p>char* CMySQLMan::GetHostInfo()<br>{<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}<br>&nbsp;return const_cast&lt;char *&gt;(mysql_get_host_info(pMySql));<br>}</p>
<p>int CMySQLMan::GetProtocolInfo()<br>{<br>&nbsp;int iRet = 0;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}<br>&nbsp;iRet = mysql_get_proto_info(pMySql);<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return iRet;<br>}</p>
<p>char* CMySQLMan::GetServerInfo()<br>{<br>&nbsp;static char szRet[1024];<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}<br>&nbsp;_tcscpy(szRet, const_cast&lt;char *&gt;(mysql_get_server_info(pMySql)));<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return szRet;<br>}</p>
<p>char* CMySQLMan::GetState()<br>{<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}<br>&nbsp;static char szRet[1024];<br>&nbsp;_tcscpy(szRet,const_cast&lt;char *&gt;(mysql_stat(pMySql)));<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return szRet;<br>}</p>
<p>bool CMySQLMan::SetCharset()<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;char szSql[50];<br>&nbsp;strcpy(szSql, "set names gb2312");<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if (mysql_query(pMySql, szSql))<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>//LOCK TABLES tbl1 READ, tbl2 WRITE<br>bool CMySQLMan::LockTable(const char *TableName, const char *Priority)<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;char szSql[50];<br>&nbsp;sprintf(szSql, "LOCK TABLES %s %s", TableName, Priority);<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if (mysql_query(pMySql, szSql))<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;<br>}</p>
<p>bool CMySQLMan::UnlockTable()<br>{<br>&nbsp;bool bRet = false;<br>&nbsp;MYSQL *pMySql = GetIdleMySql();<br>&nbsp;if (pMySql == NULL)<br>&nbsp;{<br>&nbsp;&nbsp;return false;<br>&nbsp;}<br>&nbsp;if(mysql_query(pMySql,"UNLOCK TABLES"))<br>&nbsp;&nbsp;bRet = true;<br>&nbsp;SetIdleMysql(pMySql);</p>
<p>&nbsp;return bRet;</p>
<p>}</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/aurain/aggbug/43049.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-02-21 15:10 <a href="http://www.cppblog.com/aurain/archive/2008/02/21/43049.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络字节序与主机字节序</title><link>http://www.cppblog.com/aurain/archive/2008/02/18/42865.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Mon, 18 Feb 2008 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/02/18/42865.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/42865.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/02/18/42865.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/42865.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/42865.html</trackback:ping><description><![CDATA[不同的CPU有不同的字节序类型&nbsp;这些字节序是指整数在内存中保存的顺序&nbsp;这个叫做主机序&nbsp;<br>最常见的有两种<br>1．&nbsp;Little&nbsp;endian：将低序字节存储在起始地址<br>2．&nbsp;Big&nbsp;endian：将高序字节存储在起始地址<br><br>LE&nbsp;little-endian&nbsp;<br>最符合人的思维的字节序&nbsp;<br>地址低位存储值的低位&nbsp;<br>地址高位存储值的高位&nbsp;<br>怎么讲是最符合人的思维的字节序，是因为从人的第一观感来说&nbsp;<br>低位值小，就应该放在内存地址小的地方，也即内存地址低位&nbsp;<br>反之，高位值就应该放在内存地址大的地方，也即内存地址高位&nbsp;<br><br>BE&nbsp;big-endian&nbsp;<br>最直观的字节序&nbsp;<br>地址低位存储值的高位&nbsp;<br>地址高位存储值的低位&nbsp;<br>为什么说直观，不要考虑对应关系&nbsp;<br>只需要把内存地址从左到右按照由低到高的顺序写出&nbsp;<br>把值按照通常的高位到低位的顺序写出&nbsp;<br>两者对照，一个字节一个字节的填充进去&nbsp;<br><br>例子：在内存中双字0x01020304(DWORD)的存储方式&nbsp;<br><br>内存地址&nbsp;<br>4000&nbsp;4001&nbsp;4002&nbsp;4003&nbsp;<br>LE&nbsp;04&nbsp;03&nbsp;02&nbsp;01&nbsp;<br>BE&nbsp;01&nbsp;02&nbsp;03&nbsp;04&nbsp;<br><br>例子：如果我们将0x1234abcd写入到以0x0000开始的内存中，则结果为<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;big-endian&nbsp;&nbsp;little-endian<br>0x0000&nbsp;&nbsp;0x12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0xcd<br>0x0001&nbsp;&nbsp;0x23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0xab<br>0x0002&nbsp;&nbsp;0xab&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0x34<br>0x0003&nbsp;&nbsp;0xcd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0x12<br>x86系列CPU都是little-endian的字节序.&nbsp;<br><br>网络字节顺序是TCP/IP中规定好的一种数据表示格式，它与具体的CPU类型、操作系统等无关，从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big&nbsp;endian排序方式。<br><br>为了进行转换&nbsp;bsd&nbsp;socket提供了转换的函数&nbsp;有下面四个<br>htons&nbsp;把unsigned&nbsp;short类型从主机序转换到网络序<br>htonl&nbsp;把unsigned&nbsp;long类型从主机序转换到网络序<br>ntohs&nbsp;把unsigned&nbsp;short类型从网络序转换到主机序<br>ntohl&nbsp;把unsigned&nbsp;long类型从网络序转换到主机序<br><br>在使用little&nbsp;endian的系统中&nbsp;这些函数会把字节序进行转换&nbsp;<br>在使用big&nbsp;endian类型的系统中&nbsp;这些函数会定义成空宏<br><br>同样&nbsp;在网络程序开发时&nbsp;或是跨平台开发时&nbsp;也应该注意保证只用一种字节序&nbsp;不然两方的解释不一样就会产生bug.<br><br>注：<br>1、网络与主机字节转换函数:htons&nbsp;ntohs&nbsp;htonl&nbsp;ntohl&nbsp;(s&nbsp;就是short&nbsp;l是long&nbsp;h是host&nbsp;n是network)<br>2、不同的CPU上运行不同的操作系统，字节序也是不同的，参见下表。<br>处理器&nbsp;&nbsp;&nbsp;&nbsp;操作系统&nbsp;&nbsp;&nbsp;&nbsp;字节排序<br>Alpha&nbsp;&nbsp;&nbsp;&nbsp;全部&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian<br>HP-PA&nbsp;&nbsp;&nbsp;&nbsp;NT&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian<br>HP-PA&nbsp;&nbsp;&nbsp;&nbsp;UNIX&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian<br>Intelx86&nbsp;&nbsp;&nbsp;&nbsp;全部&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian&nbsp;&lt;-----x86系统是小端字节序系统<br>Motorola680x()&nbsp;&nbsp;&nbsp;&nbsp;全部&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian<br>MIPS&nbsp;&nbsp;&nbsp;&nbsp;NT&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian<br>MIPS&nbsp;&nbsp;&nbsp;&nbsp;UNIX&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian<br>PowerPC&nbsp;&nbsp;&nbsp;&nbsp;NT&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian<br>PowerPC&nbsp;&nbsp;&nbsp;&nbsp;非NT&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian&nbsp;&nbsp;&lt;-----PPC系统是大端字节序系统<br>RS/6000&nbsp;&nbsp;&nbsp;&nbsp;UNIX&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian<br>SPARC&nbsp;&nbsp;&nbsp;&nbsp;UNIX&nbsp;&nbsp;&nbsp;&nbsp;Big&nbsp;endian<br>IXP1200&nbsp;ARM核心&nbsp;&nbsp;&nbsp;&nbsp;全部&nbsp;&nbsp;&nbsp;&nbsp;Little&nbsp;endian&nbsp;<br><br>
<p>下面是一个检验本机字节序的简便方法：</p>
<p>//判断本机的字节序<br>//返回true表为小段序。返回false表示为大段序<br><font color=#0000ff>bool am_little_endian ()<br>{<br>&nbsp;unsigned short i=1;<br>&nbsp;return (int)*((char *)(&amp;i)) ? true : false;<br>}<br>int main()<br>{<br>&nbsp;&nbsp;if(am_little_endian())<br>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;printf("本机字节序为小段序!\n");<br>&nbsp;}<br>&nbsp;else<br>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("本机字节序为大段序!\n");<br>&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>}</font></p>
<img src ="http://www.cppblog.com/aurain/aggbug/42865.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-02-18 11:17 <a href="http://www.cppblog.com/aurain/archive/2008/02/18/42865.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux系统环境下的Socket编程详细解析</title><link>http://www.cppblog.com/aurain/archive/2008/01/18/socket.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Fri, 18 Jan 2008 01:41:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2008/01/18/socket.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/41397.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2008/01/18/socket.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/41397.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/41397.html</trackback:ping><description><![CDATA[&nbsp;
<p align=left><strong><span>什么是<span>Socket</span></span></strong></p>
<p align=left><span>　　<span>Socket</span>接口是<span>TCP/IP</span>网络的<span>API</span>，<span>Socket</span>接口定义了许多函数或例程，程序员可以用它们来开发<span>TCP/IP</span>网络上的应用程序。要学<span>Internet</span>上的<span>TCP/IP</span>网络编程，必须理解<span>Socket</span>接口。<span> </span></span></p>
<p align=left><span>　　<span>Socket</span>接口设计者最先是将接口放在<span>Unix</span>操作系统里面的。如果了解<span>Unix</span>系统的输入和输出的话，就很容易了解<span>Socket</span>了。网络的<span>Socket</span>数据传输是一种特殊的<span>I/O</span>，<span>Socket</span>也是一种文件描述符。<span>Socket</span>也具有一个类似于打开文件的函数调用<span>Socket()</span>，该函数返回一个整型的<span>Socket</span>描述符，随后的连接建立、数据传输等操作都是通过该<span>Socket</span>实现的。常用的<span>Socket</span>类型有两种：流式<span>Socket</span>（<span>SOCK_STREAM</span>）和数据报式<span>Socket</span>（<span>SOCK_DGRAM</span>）。流式是一种面向连接的<span>Socket</span>，针对于面向连接的<span>TCP</span>服务应用；数据报式<span>Socket</span>是一种无连接的<span>Socket</span>，对应于无连接的<span>UDP</span>服务应用。<span> </span></span></p>
<p align=left><span>　　<span>Socket</span>建立</span></p>
<p align=left><span>　　为了建立<span>Socket</span>，程序可以调用<span>socket</span>函数，该函数返回一个类似于文件描述符的句柄。<span>socket</span>函数原型为：</span></p>
<p align=left><span>　　<span>int socket(int domain, int type, int protocol); </span></span></p>
<p align=left><span>　　<span>domain</span>指明所使用的<span><span><span>协议</span></span></span>族，通常为<span>AF_INET</span>，表示<span><span><span>互联网</span></span><span><span>协议</span></span></span>族（<span>TCP/IP<span><span>协议</span></span></span>族）；<span>type</span>参数指定<span>socket</span>的类型：<span>SOCK_STREAM </span>或<span>SOCK_DGRAM</span>，<span>Socket</span>接口还定义了原始<span>Socket</span>（<span>SOCK_RAW</span>），允许程序使用低层协议；<span>protocol</span>通常赋值<span>"0"</span>（表示根据<span>type</span>来自动选择协议）。<span>socket()</span>调用返回一个整型<span>socket</span>描述符，你可以在后面的调用使用它。</span></p>
<p align=left><span>　　<span>Socket</span>描述符是一个指向内部数据结构的指针，它指向描述符表入口。调用<span>Socket</span>函数时，<span>socket</span>执行体将建立一个<span>Socket</span>，实际上<span>"</span>建立一个<span>Socket"</span>意味着为一个<span>Socket</span>数据结构分配<span><span><span>存储</span></span></span>空间。<span>Socket</span>执行体为你管理描述符表。</span></p>
<p align=left><span>　　两个网络程序之间的一个网络连接包括五种信息：通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。<span>Socket</span>数据结构中包含这五种信息。<span> </span></span></p>
<p align=left><span>　　<span>Socket</span>配置</span></p>
<p align=left><span>　　通过<span>socket</span>函数调用返回一个<span>socket</span>描述符后，在使用<span>socket</span>进行网络传输以前，必须配置该<span>socket</span>。面向连接的<span>socket</span>客户端通过调用<span>connect</span>函数在<span>socket</span>数据结构中保存本地和远端信息。无连接<span>socket</span>的客户端和服务端以及面向连接<span>socket</span>的服务端通过调用<span>bind</span>函数来配置本地信息。<span> <br>bind</span>函数将<span>socket</span>与本机上的一个端口相关联，随后你就可以在该端口监听服务请求。<span>bind</span>函数原型为：<span> </span></span></p>
<p align=left><span>　　<span> </span></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=484 border=1>
    <tbody>
        <tr>
            <td width=484>
            <p align=left><span>int bind(int sockfd,struct sockaddr *my_addr, int addrlen); <br>sockfd</span><span>是调用<span>socket</span>函数返回的<span>socket</span>描述符<span>,</span></span></p>
            <p align=left><span>my_addr</span><span>是一个指向包含有本机<span>IP</span>地址及端口号等信息的<span>sockaddr</span>类型的指针；</span></p>
            <p align=left><span>addrlen</span><span>常被设置为<span>sizeof(struct sockaddr)</span>。<span> <br></span>　　<span>struct sockaddr</span>结构类型是用来保存<span>socket</span>信息的：<span> <br></span>　　<span>struct sockaddr { <br></span>　　<span> unsigned short sa_family; /* </span>地址族， <span>AF_xxx */ <br>char sa_data[14]; /* 14 </span>字节的协议地址<span> */ <br>}; <br></span>　　<span>sa_family</span>一般为<span>AF_INET</span>，代表<span>Internet</span>（<span>TCP/IP</span>）地址族；<span>sa_data<br></span>则包含该<span>socket</span>的<span>IP</span>地址和端口号。<span> <br></span>　　另外还有一种结构类型：<span> <br></span>　　<span>struct sockaddr_in { <br></span>　　<span> short int sin_family; /* </span>地址族<span> */ <br></span>　　<span> unsigned short int sin_port; /* </span>端口号<span> */ <br></span>　　<span> struct in_addr sin_addr; /* IP</span>地址<span> */ <br></span>　　<span> unsigned char sin_zero[8]; /* </span>填充<span>0 </span>以保持与<span>struct sockaddr</span>同样大小<span> */ <br></span>　　<span>}; </span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p align=left><span>　　这个结构更方便使用。<span>sin_zero</span>用来将<span>sockaddr_in</span>结构填充到与<span>struct sockaddr</span>同样的长度，可以用<span>bzero()</span>或<span>memset()</span>函数将其置为零。指向<span>sockaddr_in </span>的指针和指向<span>sockaddr</span>的指针可以相互转换，这意味着如果一个函数所需参数类型是<span>sockaddr</span>时，你可以在函数调用的时候将一个指向<span>sockaddr_in</span>的指针转换为指向<span>sockaddr</span>的指针；或者相反。<span> </span></span></p>
<p align=left><span>　　使用<span>bind</span>函数时，可以用下面的赋值实现自动获得本机<span>IP</span>地址和随机获取一个没有被占用的端口号：<span> </span></span></p>
<p align=left><span>　　<span>my_addr.sin_port = 0; /* </span>系统随机选择一个未被使用的端口号<span> */ <br></span>　　<span>my_addr.sin_addr.s_addr = INADDR_ANY; /* </span>填入本机<span>IP</span>地址<span> */ <br></span>通过将<span>my_addr.sin_port</span>置为<span>0</span>，函数会自动为你选择一个未占用的端口来使用。同样，通过将<span>my_addr.sin_addr.s_addr</span>置为<span>INADDR_ANY</span>，系统会自动填入本机<span>IP</span>地址。</span></p>
<p align=left><span>　　注意在使用<span>bind</span>函数是需要将<span>sin_port</span>和<span>sin_addr</span>转换成为网络字节优先顺序；而<span>sin_family</span>则不需要转换。</span></p>
<p align=left><span>　　计算机数据<span><span><span>存储</span></span></span>有两种字节优先顺序：高位字节优先和低位字节优先。<span>Internet</span>上数据以高位字节优先顺序在网络上传输，所以对于在内部是以低位字节优先方式存储数据的机器，在<span>Internet</span>上传输数据时就需要进行转换，否则就会出现数据不一致。</span></p>
<p align=left><span>　　下面是几个字节顺序转换函数：<span> </span></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=400 border=1>
    <tbody>
        <tr>
            <td>
            <p align=left><span>&#183;htonl()</span><span>：把<span>32</span>位值从主机字节序转换成网络字节序<span> <br>&#183;htons()</span>：把<span>16</span>位值从主机字节序转换成网络字节序<span> <br>&#183;ntohl()</span>：把<span>32</span>位值从网络字节序转换成主机字节序<span> <br>&#183;ntohs()</span>：把<span>16</span>位值从网络字节序转换成主机字节序<span> </span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p align=left><span>　　<span>bind()</span>函数在成功被调用时返回<span>0</span>；出现错误时返回<span>"-1"</span>并将<span>errno</span>置为相应的错误号。需要注意的是，在调用<span>bind</span>函数时一般不要将端口号置为小于<span>1024</span>的值，因为<span>1</span>到<span>1024</span>是保留端口号，你可以选择大于<span>1024</span>中的任何一个没有被占用的端口号。</span></p>
<p align=left><strong><span>连接建立<span> </span></span></strong></p>
<p align=left><span>面向连接的客户程序使用<span>connect</span>函数来配置<span>socket</span>并与远端<span><span><span>服务器</span></span></span>建立一个<span>TCP</span>连接，其函数原型为：</span></p>
<p align=left><span>int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); <br>sockfd</span><span>是<span>socket</span>函数返回的<span>socket</span>描述符；<span>serv_addr</span>是包含远端主机<span>IP</span>地址和端口的指针；<span>addrlen</span>是远端地址结构的长度<span>(sizeof(struct sockaddr))</span>。<span>connect</span>函数在出现错误时返回<span>-1</span>，并且设置<span>errno</span>为相应的错误码。进行客户端程序设计无须调用<span>bind()</span>，因为这种情况下只需知道目的机器的<span>IP</span>地址，而客户通过哪个端口与<span><span><span>服务器</span></span></span>建立连接并不需要关心，<span>socket</span>执行体为你的程序自动选择一个未被占用的端口，并通知你的程序数据什么时候到打断口。</span></p>
<p align=left><span>　　<span>connect</span>函数启动和远端主机的直接连接。只有面向连接的客户程序使用<span>socket</span>时才需要将此<span>socket</span>与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接，它只是被动的在协议端口监听客户的请求。<span> </span></span></p>
<p align=left><span>　　<span>listen</span>函数使<span>socket</span>处于被动的监听模式，并为该<span>socket</span>建立一个输入数据队列，将到达的服务请求保存在此队列中，直到程序处理它们。</span></p>
<p align=left><span>　　<span>int listen(int sockfd</span>，<span> int backlog); </span></span></p>
<p align=left><span>　　<span>sockfd</span>是<span>Socket</span>系统调用返回的<span>socket </span>描述符；<span>backlog</span>指定在请求队列中允许的最大请求数，进入的连接请求将在队列中等待<span>accept()</span>它们（参考下文）。<span>backlog</span>对队列中等待服务的请求的数目进行了限制，大多数系统缺省值为<span>20</span>。如果一个服务请求到来时，输入队列已满，该<span>socket</span>将拒绝连接请求，客户将收到一个出错信息。</span></p>
<p align=left><span>　　当出现错误时<span>listen</span>函数返回<span>-1</span>，并置相应的<span>errno</span>错误码。</span></p>
<p align=left><span>　　<span>accept()</span>函数让服务器接收客户的连接请求。在建立好输入队列后，服务器就调用<span>accept</span>函数，然后睡眠并等待客户的连接请求。</span></p>
<p align=left><span>　　<span>int accept(int sockfd, void *addr, int *addrlen); </span></span></p>
<p align=left><span>　　<span>sockfd</span>是被监听的<span>socket</span>描述符，<span>addr</span>通常是一个指向<span>sockaddr_in</span>变量的指针，该变量用来存放提出连接请求服务的主机的信息（某台主机从某个端口发出该请求）；<span>addrlen</span>通常为一个指向值为<span>sizeof(struct sockaddr_in)</span>的整型指针变量。出现错误时<span>accept</span>函数返回<span>-1</span>并置相应的<span>errno</span>值。</span></p>
<p align=left><span>　　首先，当<span>accept</span>函数监视的<span>socket</span>收到连接请求时，<span>socket</span>执行体将建立一个新的<span>socket</span>，执行体将这个新<span>socket</span>和请求连接进程的地址联系起来，收到服务请求的初始<span>socket</span>仍可以继续在以前的<span> socket</span>上监听，同时可以在新的<span>socket</span>描述符上进行数据传输操作。<span> <br><br></span>　　数据传输</span></p>
<p align=left><span>　　<span>send()</span>和<span>recv()</span>这两个函数用于面向连接的<span>socket</span>上进行数据传输。<span> </span></span></p>
<p align=left><span>　　<span>send()</span>函数原型为：<span> </span></span></p>
<p align=left><span>　　<span>int send(int sockfd, const void *msg, int len, int flags); <br>sockfd</span>是你想用来传输数据的<span>socket</span>描述符；<span>msg</span>是一个指向要发送数据的指针；<span>len</span>是以字节为单位的数据的长度；<span>flags</span>一般情况下置为<span>0</span>（关于该参数的用法可参照<span>man</span>手册）。<span> </span></span></p>
<p align=left><span>　　<span>send()</span>函数返回实际上发送出的字节数，可能会少于你希望发送的数据。在程序中应该将<span>send()</span>的返回值与欲发送的字节数进行比较。当<span>send()</span>返回值与<span>len</span>不匹配时，应该对这种情况进行处理。<span> <br>char *msg = "Hello!"; <br>int len, bytes_sent; <br>&#8230;&#8230; <br>len = strlen(msg); <br>bytes_sent = send(sockfd, msg,len,0); <br>&#8230;&#8230; <br></span>　　<span>recv()</span>函数原型为：</span></p>
<p align=left><span>　　<span>int recv(int sockfd,void *buf,int len,unsigned int flags); </span></span></p>
<p align=left><span>　　<span>sockfd</span>是接受数据的<span>socket</span>描述符；<span>buf </span>是存放接收数据的缓冲区；<span>len</span>是缓冲的长度。<span>Flags</span>也被置为<span>0</span>。<span>recv()</span>返回实际上接收的字节数，当出现错误时，返回<span>-1</span>并置相应的<span>errno</span>值。<span> </span></span></p>
<p align=left><span>　　<span>sendto()</span>和<span>recvfrom()</span>用于在无连接的数据报<span>socket</span>方式下进行数据传输。由于本地<span>socket</span>并没有与远端机器建立连接，所以在发送数据时应指明目的地址。<span> <br></span>　　<span>sendto()</span>函数原型为：<span> <br></span>　　<span>int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen); </span></span></p>
<p align=left><span>　　该函数比<span>send()</span>函数多了两个参数，<span>to</span>表示目地机的<span>IP</span>地址和端口号信息，而<span>tolen</span>常常被赋值为<span>sizeof (struct sockaddr)</span>。<span>sendto </span>函数也返回实际发送的数据字节长度或在出现发送错误时返回<span>-1</span>。<span> </span></span></p>
<p align=left><span>　　<span>recvfrom()</span>函数原型为：<span> </span></span></p>
<p align=left><span>　　<span>int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen); </span></span></p>
<p align=left><span>　　<span>from</span>是一个<span>struct sockaddr</span>类型的变量，该变量保存源机的<span>IP</span>地址及端口号。<span>fromlen</span>常置为<span>sizeof (struct sockaddr)</span>。当<span>recvfrom()</span>返回时，<span>fromlen</span>包含实际存入<span>from</span>中的数据字节数。<span>recvfrom()</span>函数返回接收到的字节数或当出现错误时返回<span>-1</span>，并置相应的<span>errno</span>。<span> </span></span></p>
<p align=left><span>　　如果你对数据报<span>socket</span>调用了<span>connect()</span>函数时，你也可以利用<span>send()</span>和<span>recv()</span>进行数据传输，但该<span>socket</span>仍然是数据报<span>socket</span>，并且利用传输层的<span>UDP</span>服务。但在发送或接收数据报时，内核会自动为之加上目地和源地址信息。<span> <br><br></span>　　结束传输<span> </span></span></p>
<p align=left><span>　　当所有的数据操作结束以后，你可以调用<span>close()</span>函数来释放该<span>socket</span>，从而停止在该<span>socket</span>上的任何数据操作：<span> </span></span></p>
<p align=left><span>　　<span>close(sockfd); </span></span></p>
<p align=left><span>　　你也可以调用<span>shutdown()</span>函数来关闭该<span>socket</span>。该函数允许你只停止在某个方向上的数据传输，而一个方向上的数据传输继续进行。如你可以关闭某<span>socket</span>的写操作而允许继续在该<span>socket</span>上接受数据，直至读入所有数据。<span> </span></span></p>
<p align=left><span>　　<span>int shutdown(int sockfd,int how); </span></span></p>
<p align=left><span>　　<span>sockfd</span>是需要关闭的<span>socket</span>的描述符。参数<span> how</span>允许为<span>shutdown</span>操作选择以下几种方式：<span> <br>&#183;0-------</span>不允许继续接收数据<span> <br>&#183;1-------</span>不允许继续发送数据<span> <br>&#183;2-------</span>不允许继续发送和接收数据，<span> <br>&#183;</span>均为不允许则调用<span>close() </span></span></p>
<p align=left><span>　　<span>shutdown</span>在操作成功时返回<span>0</span>，在出现错误时返回<span>-1</span>并置相应<span>errno</span>。<span> </span></span></p>
<p>&nbsp;</p>
<p align=left><strong><span>面向连接的<span>Socket</span>实例<span> </span></span></strong></p>
<p align=left><span>　　代码实例中的服务器通过<span>socket</span>连接向客户端发送字符串<span>"Hello, you are connected!"</span>。只要在服务器上运行该服务器软件，在客户端运行客户软件，客户端就会收到该字符串。<span> </span></span></p>
<p align=left><span>　　该服务器软件代码如下：<span> <br><br clear=all></span></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=460 border=1>
    <tbody>
        <tr>
            <td width=460>
            <p align=left><span>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#define SERVPORT 3333 /*</span><span>服务器监听端口号<span> */ <br>#define BACKLOG 10 /* </span>最大同时连接请求数<span> */ <br>main() <br>{ <br>int sockfd,client_fd; /*sock_fd</span>：监听<span>socket</span>；<span>client_fd</span>：数据传输<span>socket */ <br></span>　<span>struct sockaddr_in my_addr; /* </span>本机地址信息<span> */ <br></span>　<span>struct sockaddr_in remote_addr; /* </span>客户端地址信息<span> */ <br>if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { <br></span>　　<span>perror("socket</span>创建出错！<span>"); exit(1); <br>} <br>my_addr.sin_family=AF_INET; <br></span>　<span>my_addr.sin_port=htons(SERVPORT); <br></span>　<span>my_addr.sin_addr.s_addr = INADDR_ANY; <br>bzero(&amp;(my_addr.sin_zero),8); <br></span>　<span>if (bind(sockfd, (struct sockaddr *)&amp;my_addr, sizeof(struct sockaddr)) \ <br></span>　　<span> == -1) { <br>perror("bind</span>出错！<span>"); <br>exit(1); <br>} <br></span>　<span>if (listen(sockfd, BACKLOG) == -1) { <br>perror("listen</span>出错！<span>"); <br>exit(1); <br>} <br>while(1) { <br></span>　　<span>sin_size = sizeof(struct sockaddr_in); <br></span>　　<span>if ((client_fd = accept(sockfd, (struct sockaddr *)&amp;remote_addr, \ <br></span>　　<span>&amp;sin_size)) == -1) { <br>perror("accept</span>出错<span>"); <br>continue; <br>} <br></span>　　<span>printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr)); <br></span>　<span> if (!fork()) { /* </span>子进程代码段<span> */ <br></span>　　<span> if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1) <br></span>　　<span> perror("send</span>出错！<span>"); <br>close(client_fd); <br>exit(0); <br>} <br></span>　　<span>close(client_fd); <br></span>　　<span>} <br></span>　<span>} <br>} </span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p align=left><span>　　服务器的工作流程是这样的：首先调用<span>socket</span>函数创建一个<span>Socket</span>，然后调用<span>bind</span>函数将其与本机地址以及一个本地端口号绑定，然后调用<span>listen</span>在相应的<span>socket</span>上监听，当<span>accpet</span>接收到一个连接服务请求时，将生成一个新的<span>socket</span>。服务器显示该客户机的<span>IP</span>地址，并通过新的<span>socket</span>向客户端发送字符串<span>"Hello</span>，<span>you are connected!"</span>。最后关闭该<span>socket</span>。</span></p>
<p align=left><span>　　代码实例中的<span>fork()</span>函数生成一个子进程来处理数据传输部分，<span>fork()</span>语句对于子进程返回的值为<span>0</span>。所以包含<span>fork</span>函数的<span>if</span>语句是子进程代码部分，它与<span>if</span>语句后面的父进程代码部分是并发执行的。<span> <br><br></span>　　客户端程序代码如下：<span> </span></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=466 border=1>
    <tbody>
        <tr>
            <td width=466>
            <p align=left><span>#include <br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#define SERVPORT 3333 <br>#define MAXDATASIZE 100 /*</span><span>每次最大数据传输量<span> */ <br>main(int argc, char *argv[]){ <br></span>　<span>int sockfd, recvbytes; <br></span>　<span>char buf[MAXDATASIZE]; <br></span>　<span>struct hostent *host; <br></span>　<span>struct sockaddr_in serv_addr; <br></span>　<span>if (argc &lt; 2) { <br>fprintf(stderr,"Please enter the server's hostname!\n"); <br>exit(1); <br>} <br></span>　<span>if((host=gethostbyname(argv[1]))==NULL) { <br>herror("gethostbyname</span>出错！<span>"); <br>exit(1); <br>} <br></span>　<span>if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ <br>perror("socket</span>创建出错！<span>"); <br>exit(1); <br>} <br></span>　<span>serv_addr.sin_family=AF_INET; <br></span>　<span>serv_addr.sin_port=htons(SERVPORT); <br></span>　<span>serv_addr.sin_addr = *((struct in_addr *)host-&gt;h_addr); <br></span>　<span>bzero(&amp;(serv_addr.sin_zero),8); <br></span>　<span>if (connect(sockfd, (struct sockaddr *)&amp;serv_addr, \ <br></span>　　<span> sizeof(struct sockaddr)) == -1) { <br>perror("connect</span>出错！<span>"); <br>exit(1); <br>} <br></span>　<span>if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) { <br>perror("recv</span>出错！<span>"); <br>exit(1); <br>} <br></span>　<span>buf[recvbytes] = '\0'; <br></span>　<span>printf("Received: %s",buf); <br></span>　<span>close(sockfd); <br>} </span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>&nbsp;</p>
<p align=left><span>客户端程序首先通过服务器域名获得服务器的<span>IP</span>地址，然后创建一个<span>socket</span>，调用<span>connect</span>函数与服务器建立连接，连接成功之后接收从服务器发送过来的数据，最后关闭<span>socket</span>。</span></p>
<p align=left><span>　　函数<span>gethostbyname()</span>是完成域名转换的。由于<span>IP</span>地址难以记忆和读写，所以为了方便，人们常常用域名来表示主机，这就需要进行域名和<span>IP</span>地址的转换。函数原型为：</span></p>
<p align=left><span><br clear=all></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=429 border=1>
    <tbody>
        <tr>
            <td width=429>
            <p align=left><span>　　<span>struct hostent *gethostbyname(const char *name); <br></span>　　函数返回为<span>hosten</span>的结构类型，它的定义如下：<span> <br></span>　　<span>struct hostent { <br></span>　<span> char *h_name; /* </span>主机的官方域名<span> */ <br></span>　　<span> char **h_aliases; /* </span>一个以<span>NULL</span>结尾的主机别名数组<span> */ <br></span>　　<span> int h_addrtype; /* </span>返回的地址类型，在<span>Internet</span>环境下为<span>AF-INET */ <br></span>　　<span>int h_length; /* </span>地址的字节长度<span> */ <br></span>　　<span> char **h_addr_list; /* </span>一个以<span>0</span>结尾的数组，包含该主机的所有地址<span>*/ <br></span>　　<span>}; <br></span>　　<span>#define h_addr h_addr_list[0] /*</span>在<span>h-addr-list</span>中的第一个地址<span>*/ </span></span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p align=left><span>　　当<span> gethostname()</span>调用成功时，返回指向<span>struct hosten</span>的指针，当调用失败时返回<span>-1</span>。当调用<span>gethostbyname</span>时，你不能使用<span>perror()</span>函数来输出错误信息，而应该使用<span>herror()</span>函数来输出。<span> <br><br></span>　　无连接的客户<span>/</span>服务器程序的在原理上和连接的客户<span>/</span>服务器是一样的，两者的区别在于无连接的客户<span>/</span>服务器中的客户一般不需要建立连接，而且在发送接收数据时，需要指定远端机的地址。<span> <br><br></span>　　阻塞和非阻塞</span></p>
<p align=left><span>　　阻塞函数在完成其指定的任务以前不允许程序调用另一个函数。例如，程序执行一个读数据的函数调用时，在此函数完成读操作以前将不会执行下一程序语句。当服务器运行到<span>accept</span>语句时，而没有客户连接服务请求到来，服务器就会停止在<span>accept</span>语句上等待连接服务请求的到来。这种情况称为阻塞（<span>blocking</span>）。而非阻塞操作则可以立即完成。比如，如果你希望服务器仅仅注意检查是否有客户在等待连接，有就接受连接，否则就继续做其他事情，则可以通过将<span>Socket</span>设置为非阻塞方式来实现。非阻塞<span>socket</span>在没有客户在等待时就使<span>accept</span>调用立即返回。<span> <br></span>　　<span>#include <br></span>　　<span>#include <br></span>　　<span>&#8230;&#8230; <br>sockfd = socket(AF_INET,SOCK_STREAM,0); <br>fcntl(sockfd,F_SETFL,O_NONBLOCK)</span>；<span> <br>&#8230;&#8230; </span></span></p>
<p align=left><span>　　通过设置<span>socket</span>为非阻塞方式，可以实现<span>"</span>轮询<span>"</span>若干<span>Socket</span>。当企图从一个没有数据等待处理的非阻塞<span>Socket</span>读入数据时，函数将立即返回，返回值为<span>-1</span>，并置<span>errno</span>值为<span>EWOULDBLOCK</span>。但是这种<span>"</span>轮询<span>"</span>会使<span>CPU</span>处于忙等待方式，从而降低性能，浪费系统资源。而调用<span>select()</span>会有效地解决这个问题，它允许你把进程本身挂起来，而同时使系统内核监听所要求的一组文件描述符的任何活动，只要确认在任何被监控的文件描述符上出现活动，<span>select()</span>调用将返回指示该文件描述符已准备好的信息，从而实现了为进程选出随机的变化，而不必由进程本身对输入进行测试而浪费<span>CPU</span>开销。<span>select</span>函数原型为<span>: <br>int select(int numfds,fd_set *readfds,fd_set *writefds</span>，<span> <br>fd_set *exceptfds,struct timeval *timeout); </span></span></p>
<p align=left><span>　　其中<span>readfds</span>、<span>writefds</span>、<span>exceptfds</span>分别是被<span>select()</span>监视的读、写和异常处理的文件描述符集合。如果你希望确定是否可以从标准输入和某个<span>socket</span>描述符读取数据，你只需要将标准输入的文件描述符<span>0</span>和相应的<span>sockdtfd</span>加入到<span>readfds</span>集合中；<span>numfds</span>的值是需要检查的号码最高的文件描述符加<span>1</span>，这个例子中<span>numfds</span>的值应为<span>sockfd+1</span>；当<span>select</span>返回时，<span>readfds</span>将被修改，指示某个文件描述符已经准备被读取，你可以通过<span>FD_ISSSET()</span>来测试。为了实现<span>fd_set</span>中对应的文件描述符的设置、复位和测试，它提供了一组宏：<span> <br></span>　　<span>FD_ZERO(fd_set *set)----</span>清除一个文件描述符集；<span> <br></span>　　<span>FD_SET(int fd,fd_set *set)----</span>将一个文件描述符加入文件描述符集中；<span> <br></span>　　<span>FD_CLR(int fd,fd_set *set)----</span>将一个文件描述符从文件描述符集中清除；<span> <br></span>　　<span>FD_ISSET(int fd,fd_set *set)----</span>试判断是否文件描述符被置位。<span> <br></span>　　<span>Timeout</span>参数是一个指向<span>struct timeval</span>类型的指针，它可以使<span>select()</span>在等待<span>timeout</span>长时间后没有文件描述符准备好即返回。<span>struct timeval</span>数据结构为：<span> <br></span>　　<span>struct timeval { <br></span>　　<span> int tv_sec; /* seconds */ <br></span>　　<span> int tv_usec; /* microseconds */ }; <br><br></span>　　<span>POP3</span>客户端实例<span> </span></span></p>
<p align=left><span>　　下面的代码实例基于<span>POP3</span>的客户协议，与邮件服务器连接并取回指定用户帐号的邮件。与邮件服务器交互的命令存储在字符串数组<span>POPMessage</span>中，程序通过一个<span>do-while</span>循环依次发送这些命令。<span> </span></span></p>
<div align=center>
<table cellSpacing=0 cellPadding=0 width=517 border=1>
    <tbody>
        <tr>
            <td width=517>
            <p align=left><span>#include <br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#include&nbsp;<br>#define POP3SERVPORT 110 <br>#define MAXDATASIZE 4096 </span></p>
            <p align=left><span>main(int argc, char *argv[]){ <br>int sockfd; <br>struct hostent *host; <br>struct sockaddr_in serv_addr; <br>char *POPMessage[]={ <br>"USER userid\r\n", <br>"PASS password\r\n", <br>"STAT\r\n", <br>"LIST\r\n", <br>"RETR 1\r\n", <br>"DELE 1\r\n", <br>"QUIT\r\n", <br>NULL <br>}; <br>int iLength; <br>int iMsg=0; <br>int iEnd=0; <br>char buf[MAXDATASIZE]; </span></p>
            <p align=left><span>if((host=gethostbyname("your.server"))==NULL) { <br>perror("gethostbyname error"); <br>exit(1); <br>} <br>if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ <br>perror("socket error"); <br>exit(1); <br>} <br>serv_addr.sin_family=AF_INET; <br>serv_addr.sin_port=htons(POP3SERVPORT); <br>serv_addr.sin_addr = *((struct in_addr *)host-&gt;h_addr); <br>bzero(&amp;(serv_addr.sin_zero),8); <br>if (connect(sockfd, (struct sockaddr *)&amp;serv_addr,sizeof(struct sockaddr))==-1){ <br>perror("connect error"); <br>exit(1); <br>} </span></p>
            <p align=left><span>do { <br>send(sockfd,POPMessage[iMsg],strlen(POPMessage[iMsg]),0); <br>printf("have sent: %s",POPMessage[iMsg]); </span></p>
            <p align=left><span>iLength=recv(sockfd,buf+iEnd,sizeof(buf)-iEnd,0); <br>iEnd+=iLength; <br>buf[iEnd]='\0'; <br>printf("received: %s,%d\n",buf,iMsg); </span></p>
            <p align=left><span>iMsg++; <br>} while (POPMessage[iMsg]); </span></p>
            <p align=left><span>close(sockfd); <br>} </span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/aurain/aggbug/41397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2008-01-18 09:41 <a href="http://www.cppblog.com/aurain/archive/2008/01/18/socket.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>inet_addr函数的实现</title><link>http://www.cppblog.com/aurain/archive/2007/12/05/37855.html</link><dc:creator>水</dc:creator><author>水</author><pubDate>Wed, 05 Dec 2007 07:58:00 GMT</pubDate><guid>http://www.cppblog.com/aurain/archive/2007/12/05/37855.html</guid><wfw:comment>http://www.cppblog.com/aurain/comments/37855.html</wfw:comment><comments>http://www.cppblog.com/aurain/archive/2007/12/05/37855.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/aurain/comments/commentRss/37855.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aurain/services/trackbacks/37855.html</trackback:ping><description><![CDATA[<p>输入是点分的IP地址格式（如A.B.C.D)的字符串，从该字符串中提取出每一部分，转换为ULONG,假设得到4个ULONG型的A,B,C,D,<br>ulAddress（ULONG型）是转换后的结果，<br>ulAddress = D&lt;&lt;24 + C&lt;&lt;16 + B&lt;&lt;8 + A(网络字节序），即inet_addr(const char *)的返回结果<br>另外，我们也可以得到把该IP转换为主机序的结果，转换方法一样<br>A&lt;&lt;24 + B&lt;&lt;16 + C&lt;&lt;8 + D<font style="BACKGROUND-COLOR: #cce8cf"></font></p>
<img src ="http://www.cppblog.com/aurain/aggbug/37855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aurain/" target="_blank">水</a> 2007-12-05 15:58 <a href="http://www.cppblog.com/aurain/archive/2007/12/05/37855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>