??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品国产清自在天天线 ,亚洲AV无码1区2区久久,久久亚洲精品无码观看不卡http://www.shnenglu.com/lf426/category/7197.htmlGame Design Using C++ and SDLzh-cnMon, 07 Jun 2010 03:24:51 GMTMon, 07 Jun 2010 03:24:51 GMT60socket ~程入门教程Q三QTCP原理Q?、设计TCP socket的类Q下Q?/title><link>http://www.shnenglu.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.shnenglu.com/lf426/archive/2010/06/07/117299.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/117299.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/07/117299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/117299.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/117299.html</trackback:ping><description><![CDATA[在另外一边的客户端,我们分析一下TCPClientSock的徏立过E?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"> TCPClientSock: </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    sockaddr_in serverSockAddr;<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> preBuffer;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> preBufferSize;<br>    mutable </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> preReceivedLength;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    TCPClientSock(<br>        </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> server_IP,<br>        unsigned </span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000"> server_port,<br>        </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> pre_buffer_size </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">);<br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPClientSock();<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> TCPReceive() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> TCPSend(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> send_data,<br>            </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> data_length) </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>                    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">server_IP,<br>                    unsigned </span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000"> server_port,<br>                    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> pre_buffer_size):<br>preBufferSize(pre_buffer_size),<br>preReceivedLength(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br>{<br>    preBuffer </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">[preBufferSize];<br><br>    sockFD </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (sockFD </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br>        sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">sock() failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>    }<br><br>    memset(</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">serverSockAddr, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr));<br>    serverSockAddr.sin_family </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> AF_INET;<br>    serverSockAddr.sin_addr.s_addr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> inet_addr(server_IP);<br>    serverSockAddr.sin_port </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> htons(server_port);<br><br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (connect(sockFD,<br>                (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">serverSockAddr,<br>                </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(serverSockAddr)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>        sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">connect() failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>    }<br>}<br><br>TCPClientSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPClientSock()<br>{<br>    delete [] preBuffer;<br>    close(sockFD);<br>}</span></div> TCPClientSock通过socket()建立起sockFDQ然后指定服务器的serverSockAddrQ然后通过connect()向serverSockAddr指定的服务器发出握手h。需要说明的是,调用connect()的时候,pȝ会检查TCPClientSock的sockFD是否已经l定了本机的SockAddrQ事实上我们也可以通过bind()本机的IP和指定的端口L定在q个sockFD上,但是我们q不兛_q个IP地址和端口号Q况且很多主机ƈ没有公网IPQ特别在中国Q,所以通常我们不自己去l定Q这Ll就会帮我们完成l定工作Q分配一个空闲的端口号作为本机地址的端口号?br>q样TCPClientSockh来向Q本机地址Q通常ql自动完成绑定,也可以指定)和去向(指定的server端地址Q的地址信息Q所以可以收发信息。于是,TCPClientSock发出的第一个数据报是发lserver监听socket的握手请求数据报QTCPListenSock接收q个数据报后Q将相关信息传递给TCPServerSock建立新的sockFDQ我们上一节讲刎ͼq个新的sockFD建立h之后马上向client端返回一个数据报Q一斚w表示接受W一ơ握手请求,另外一斚w发出W二ơ握手请求?br>收到W二ơ握手请求后Qconnect()才会q回Q不然就会阻塞,非常“力”的去q接server。这?#8220;力”的程度跟pȝ有关Q在我的试验中,windows下很快,几U;而Debian则接q?分钟Q?br>connect()q回的同Ӟ向server发出了第三次握手的信息,q个信息是对W二ơ握手请求的认可。所以,W一ơ和W二ơ握手包含着q接的请求;而第二次和第三次握手则包含着Ҏ手请求的认可Q他们都是在告诉ҎQ我知道q同意你q接上我了?br>xQTCP三次握手的概念在socket中完整的实现Q徏立v数据的TCP通信通道? <img src ="http://www.shnenglu.com/lf426/aggbug/117299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-07 00:46 <a href="http://www.shnenglu.com/lf426/archive/2010/06/07/117299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket ~程入门教程Q三QTCP原理Q?、设计TCP socket的类Q中Q?http://www.shnenglu.com/lf426/archive/2010/06/06/117297.htmllf426lf426Sun, 06 Jun 2010 15:46:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/06/117297.htmlhttp://www.shnenglu.com/lf426/comments/117297.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/06/117297.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/117297.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117297.html
class TCPServerSock: public BaseSock{
private:
    sockaddr_in clientSockAddr;
protected:
    
char* preBuffer;
    
int preBufferSize;
    mutable 
int preReceivedLength;
public:
    
explicit TCPServerSock(
        
const TCPListenSock& listen_sock,
        
int pre_buffer_size = 32);
    
virtual ~TCPServerSock();
    
int TCPReceive() const;
    
int TCPSend(const char* send_data,
            
const int& data_length) const;
};
q里Q我们ؓTCPServerSock预留一个缓存,q个~存q不是必ȝQ但是设|这样一个缓存至有两个好处Q?br>1、可以在使用时不必专门ؓrecv()建立~存Q?br>2、类ҎTCPReceive()和TCPSend()可以׃nq个~存Q在处理很多问题时候很方便Q比如echoQ就不需要先把recv()的缓存读出来再由send()来发送?br>缓存已用长度preReceiveLength加上关键字mutable表示我们不关心这个长度会被更改,我们只在乎有一个缓存可以用Q但是实际用了多不重要Q这h们就可以为接受和发送的cL法加上const?br>我们回到TCPServerSock的徏立,TCPServerSock通过TCPListenSock accept()一个远E的client connect()握手h而徏立,所以,TCPServerSock的构造在默认情况下是d的?br>
TCPServerSock::TCPServerSock(
                
const TCPListenSock& listen_sock,
                
int pre_buffer_size):
preBufferSize(pre_buffer_size),
preReceivedLength(
0)
{
    preBuffer 
= new char[preBufferSize];

    socklen_t
 clientSockAddrLen = sizeof(clientSockAddr);
    sockFD 
= accept(    listen_sock.showSockFD(),
                        (sockaddr
*)&clientSockAddr,
                        
&clientSockAddrLen);
    
if (sockFD < 0) {
        sockClass::error_info(
"accept() failed.");
    }
    std::cout    
<< "Client (IP: "
                
<< inet_ntoa(clientSockAddr.sin_addr)
                
<< ") conneted." << std::endl;
}

TCPServerSock::
~TCPServerSock()
{
    delete [] preBuffer;
    close(sockFD);
}
q里需要注意一个Linux和Windows下的不同Q?br>对于sockaddr_inQ也包括sockaddrQ的大小Q被accept()指定的时候,Linux中用的是socklen_tQ其实这是size_tQ也是unsigned int。而WinSock中却用的是int。因为在~译中不会自动{换,所以会提示错误?br>再次QTCPServerSock的sockFD是通过accept()建立的而不是socket()Q这也是唯一一个不用socket()建立的sockFDQ包括UDP的)。在client发出的connect()握手h的数据报中,同时包含着client端的地址信息QIP地址和端口)和server端的地址信息QIP地址和端口)Q正是这个握手请求数据报中的两边的地址信息通过accept()被传递到TCPServerSock的sockFD中。请注意Qserver端的信息q由TCPListenSock提供Q因为TCPListenSock中listenSockAddr的IP地址为空QINADDR_ANY == 0Q,而TCPServerSock中server端的SockAddr却是具体的,由客L的握手协议传来的Q但是没有具体的体现出来Q。只有具体的地址QIP地址和端口)才能提供IP数据包的目的地方向。而端口号Q则因ؓclient事先知道监听端口P从而在握手h中包含,最l传递给TCPListenSock中server端的SockAddrQ虽然这个过E决定了q个端口L于监听端口号Q但是需要明白的是,q个端口h自握手请求的数据报而不是TCPListenSock的listenSockAddr?br>新的sockFDh来向Q本机)和去向(q程Q的信息Q所以可以收发数据。TCPServerSock的sockFD一旦徏立,马上向远E返回一个数据报Q这个数据报有两层意义:
1、表Cserver已经接收了client的握手请求;
2、对client发出与serverq个新sockFD握手的请求?br>q就是所谓第二次握手Qƈ且也是以数据报的形式传送的。我们说q,TCP协议的目标是建立“可靠”的数据流形式的通讯Q在q个数据的通道建立h以前Q只能采用数据报的Ş式传送数据?

lf426 2010-06-06 23:46 发表评论
]]>
socket ~程入门教程Q三QTCP原理Q?、设计TCP socket的类Q上Q?/title><link>http://www.shnenglu.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.shnenglu.com/lf426/archive/2010/06/06/117289.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/117289.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/06/117289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/117289.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/117289.html</trackback:ping><description><![CDATA[我们在第1节中讲过Qsocket是一个int的文件描q符QWinSock中直接是一U抽象的描述W)Q我们通过对这个描q符发出指o操作socket。这是C语言的思想Q在面向对象的思想中,最好socket本n是一U对象,各种Ҏ由对象本w发出。用面向对象的思想装socketq不困难Q而且Q对于描qsocket的概念可能更加直观,q一节,我们边介lsocket和TCP的概念边对socketq行OO装?br>首先Q每一个socket对象都具有唯一的socket文g描述W,q样可以很好的对应socket的概c所以我们构Z个基c,q让其成为纯虚函数——这是因为socket文g描述W必d具体的构造中才能出现Q然后仍然保留一个返回原始的socket文g描述W的接口Q这是ؓ了不方便归结到类函数中的函数所预留准备的,比如极其重要的select()我们会在后面讲到Q所谓有备无患?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"> BaseSock{<br></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sockFD;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    BaseSock();<br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">BaseSock() </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> showSockFD() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br></span></div> 函数实现Q?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 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"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> BaseSock::showSockFD() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> sockFD;<br>}</span></div> 我们把sockFD的初始D|ؓ-1Q表明在没有zcL造的时候这是一个非法的文g描述W号QFile DescriptorQ?br>接下来,我们单回一下第一节对于TCP Server的徏立:<br>首先Q我们需要徏立一个监听socketQ然后激zd监听Q?br>然后Q在client端连接信息过来之后,通过监听端口客L的信息传递给新的socketQ从而徏立通讯socket?br>我们先构建listen socketQ?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"> TCPListenSock: </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> BaseSock{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    sockaddr_in listenSockAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">explicit</span><span style="COLOR: #000000"> TCPListenSock(unsigned </span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000"> listen_port);<br>    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock();<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> TCPListen(<br>        </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> max_connection_requests </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">) </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};</span></div> TCPListenSock建立的目的的是被动的等待client端寻找握手的connect()Q从而收集client端的sock地址信息Q包含了IP地址和端口号Q,然后在需要的时候传递给新的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 </span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000"> listen_port)<br>{<br>    sockFD </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> socket(PF_INET,<br>                    SOCK_STREAM,<br>                    IPPROTO_TCP);<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (sockFD </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br>        sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket() failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>    }<br>    memset(</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">listenSockAddr, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr));<br>    listenSockAddr.sin_family </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> AF_INET;<br>    listenSockAddr.sin_addr.s_addr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> htonl(INADDR_ANY);<br>    listenSockAddr.sin_port </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> htons(listen_port);<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (bind(    sockFD,<br>                (sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">listenSockAddr,<br>                </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(listenSockAddr)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br>        sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind() failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>    }<br>}<br><br>TCPListenSock::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">TCPListenSock()<br>{<br>    close(sockFD);<br>}</span></div> TCPListenSock通过调用socket()建立sockFDQ通过指定端口好指明监听端口,q是为客L能够扑ֈq个端口所必须的。而IP地址讄为INADDR_ANYQ其实就?Q这意味着可以是Q何一个server端所拥有的IP。TCPListenSock通过bind()sockFD和SockAddrl定在一赗这个sockFD只有本机的SockAddr意味着Q?、无法徏立连接,只有接受数据报;2、只能接受信息,因ؓ没有q程目的地的SockAddr而无法发Z息?br>而这对于TPC建立q接的过E来_既是_的,也是必须的。事实上Qclient端发出的W一个握手数据报pq个sockFD所接收Q而返回给client的握手应{和对client的握手请求则由新的sockFD发出?br>listen()是将TCPListenSockȀzMؓ监听状态,如果不激z,那么M握手的连接请求都被q个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"> TCPListenSock::TCPListen(<br>                        </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> max_connection_requests) </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (listen(    sockFD,<br>                max_connection_requests) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br>        sockClass::error_info(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen() failed.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br>    }<br>}</span></div> q个函数看来g有些多此一举,因ؓq个监听是可以整合到构造函C的,也就是说Q我们可以一旦徏立TCPListenSock׃o其激z,事实上这正是SDL_net中的做法Q也是让我感C严}的地方,因ؓ监听本n是socket的一个概c? <img src ="http://www.shnenglu.com/lf426/aggbug/117289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-06 22:24 <a href="http://www.shnenglu.com/lf426/archive/2010/06/06/117289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket ~程入门教程Q三QTCP原理Q?、socket异常信息http://www.shnenglu.com/lf426/archive/2010/06/06/117284.htmllf426lf426Sun, 06 Jun 2010 13:07:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/06/117284.htmlhttp://www.shnenglu.com/lf426/comments/117284.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/06/117284.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/117284.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117284.html因ؓsocket是属于系l的Q所以不同的pȝ对于socket有着大同异的解释,出错描述也不相同。在Linux中,socket的异怿息可以通过errno获得QintcdQ,然后可以通过函数strerror()int转换成字W串描述Q也可以通过函数perror()直接获得其描q?br>要用errno需要包含头文g<errno.h>。我使用errno获得intcȝ错误信息的一个重要原因在于,socket的异怸一定就必然DE序l止。Bjarne Stroustrup在介lC++异常机制的时候对C风格的异常机制有着q样的描qͼQC++对于异常Q的默认响应方式是终止程序。传l的反应Q对于发生异常的时候)则是装糊涂,接着做下去,以期得到最好的l果Q《C++E序设计语言》第14?异常处理Q。不q以我目前的水^看来Q终止正在进行的E序然后再通过异常机制重新启动一个新的流E,其代仯q大?#8220;装糊?#8221;的让E序l箋q行下去Q只要错误不是致命的Q通过单的判断和处理或许效果更佟?br>例如Qsocket中就有一个很有代表性的情况Q在TCPq接中,如果一Ҏ外退出——也是说没有通过TCP退出流E退出,比如没有q行完程序关闭掉socket而直接X掉或者Ctrl+c了。socket往往会因为recv()q回值小?而抛Z个异常。正常断开q接的时候,recv()会通过q回0表示q接已经断开Q但是大多数时候,我们q不希望因ؓ异常的断开导致另外一端的E序l止Q想象一下如果你xQQ腾讯的服务器E序q止是什么概?#8230;…Q,所以我们必d理这U情c?br>在Linux中,q程q接异常断开Q被重置Q的errno代码?04Q类似的Q我们应该保证出现这U异常的时候程序可以l运行?br>
//Filename: SockClass.hpp

#ifndef SOCK_CLASS_HPP
#define SOCK_CLASS_HPP

#include 
<unistd.h>
#include 
<iostream>
#include 
<sys/socket.h>
#include 
<arpa/inet.h>
#include 
<errno.h>

namespace sockClass
{
void error_info(const char* s);
}
以上是头文g中的声明Q下面是函数Q我们这里仅仅演C处理了104错误?br>
namespace sockClass
{
void error_info(const char* s)
{
    
int err_info = errno;
    std::cerr 
<< strerror(err_info) << ": errno: " << err_info << std::endl;
    
if (err_info == 104){
        
return;
    }
    exit(
1);
}
}
在windows中,错误代码由WSAGetLastError()获得Q而无需讄errno?br>
//Filename: SockClass.hpp

#ifndef SOCK_CLASS_HPP
#define SOCK_CLASS_HPP

#include 
<iostream>
#include 
<winsock2.h>

namespace sockClass
{
void error_info(const char* s);
}
WinSock的错误代码跟Linux中的不一P同样的异常,WinSock的错误代码是10054?br>q且Q由于没有errno也就无从调用strerror()Q我们最好自己写l的异常信息?br>WinSock的详l代码信息在q里Q?br>http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx
win32下的演示代码如下Q?br>
namespace sockClass
{
void error_info(const char* s)
{
    
int winsock_err = WSAGetLastError();
    perror(s);
    std::cerr 
<< "WinSock Error: " << winsock_err << std::endl;
    
if (winsock_err == WSAECONNRESET) {
        std::cerr 
<< "Connection reset by peer." << std::endl;
        
return;
    }
    exit(
1);
}
}


lf426 2010-06-06 21:07 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:8、本章的完整源代?/title><link>http://www.shnenglu.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.shnenglu.com/lf426/archive/2008/07/16/56281.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/56281.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/07/16/56281.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/56281.html</wfw:commentRss><trackback:ping>http://www.shnenglu.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: TcpServerClass.hpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#ifndef TCPSERVERCLASS_HPP_INCLUDED<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> TCPSERVERCLASS_HPP_INCLUDED</span><span style="COLOR: #000000"><br><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> TcpServer<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> listenSock;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> communicationSock;<br>    sockaddr_in servAddr;<br>    sockaddr_in clntAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> listen_port);<br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> isAccept();<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> handleEcho();<br>};<br><br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"> </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 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: TcpServerClass.cpp</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include </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"> listen_port)<br>{<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (listenSock </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">socket() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br><br>    memset(</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">servAddr, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr));<br>    servAddr.sin_family </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> AF_INET;<br>    servAddr.sin_addr.s_addr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> htonl(INADDR_ANY);<br>    servAddr.sin_port </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> htons(listen_port);<br><br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( bind(listenSock, (sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">servAddr, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(servAddr)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bind() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br><br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( listen(listenSock, </span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">listen() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>}<br><br></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> TcpServer::isAccept()<br>{<br>    unsigned </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> clntAddrLen </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(clntAddr);<br><br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (communicationSock </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> accept(listenSock, (sockaddr</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">clntAddr, </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">clntAddrLen)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>    } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Client(IP: </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> inet_ntoa(clntAddr.sin_addr) </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">) connected.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>    }<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> TcpServer::handleEcho()<br>{<br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> BUFFERSIZE </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> buffer[BUFFERSIZE];<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> recvMsgSize;<br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> goon </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><br>    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( goon </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (recvMsgSize </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> recv(communicationSock, buffer, BUFFERSIZE, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>            </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( recvMsgSize </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>            goon </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>        } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br>            </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( send(communicationSock, buffer, recvMsgSize, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> recvMsgSize ) {<br>                </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>            }<br>        }<br>    }<br><br>    close(communicationSock);<br>}</span></div> <br>演示E序Q?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: main.cpp<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Tcp Server C++ style, single work</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </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"> echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[]);<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> mainRtn </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> {<br>        mainRtn </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> echo_server(argc, argv);<br>    }<br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> s ) {<br>        perror(s);<br>        exit(EXIT_FAILURE);<br>    }<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> mainRtn;<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> echo_server(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> port;<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( argc </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000"> ) {<br>        port </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> atoi(argv[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]);<br>    } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br>        port </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5000</span><span style="COLOR: #000000">;<br>    }<br><br>    TcpServer myServ(port);<br><br>    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( myServ.isAccept() </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000"> ) {<br>            myServ.handleEcho();<br>        }<br>    }<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> <br><br> <img src ="http://www.shnenglu.com/lf426/aggbug/56281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-07-16 12:57 <a href="http://www.shnenglu.com/lf426/archive/2008/07/16/56281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket ~程入门教程Q一QTCP server 端:7、接收与发?/title><link>http://www.shnenglu.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.shnenglu.com/lf426/archive/2008/07/16/56279.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/56279.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/07/16/56279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/56279.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/56279.html</trackback:ping><description><![CDATA[作者:龙飞<br><br>        现在Q我们通过accept()创徏了新的socketQ也是我们cM的数据成员communicationSockQ现在,我们可以通过q个socketq行通讯了?br><br>TCP通讯模型<br><br>        在介l函C前,我们应该了解一些事实。TCP的Server/Client模型cMq样Q?br>ServApp——ServSock——Internet——ClntSock——ClntApp<br>当然Q我们这里的socket指的是用于“通讯”的socket。TCP的server端至有两个socketQ一个用于监听,一个用于通讯QTCP的server端可以只有一个socketQ这个socket同时“?#8221;在server的两个socket上。当Ӟ插上listen socket的目的只是ؓ了创建communication socketQ创建完备后Qlisten是可以关闭的。但是,如果q样Q其他的client无法再q接上server了?br>        我们q个模型Q是client的socket插在server的communication socket上的C意。这两个socketQ都拥有完整的本地地址信息以及q程计算机地址信息Q所以,q两个socket以及之间的网l实际上形成了一条Ş式上“闭”的管道。数据包只要从一端进来,p知道出去的目的地Q反之亦然。这正是TCP协议Q数据流形式抽象化以及实现。因Z再需要指?#8220;出处”?#8220;d”Q对q样的socketQ实际上是S/C上的socket对)的操作,如同对本地文g描述W的操作一栗但是,管我们可以使用read()和write()Q但是,Z完美的控Ӟ我们最好用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"> send(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> socket, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> msg, unsigned </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> msgLength, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> flags);<br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> recv(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> socket, </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> rcvBuffer, unsigned </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> bufferLength, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> 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 </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> Send N bytes of BUF to socket FD.  Returns the number sent or -1.<br><br>   This function is a cancellation point and therefore not marked with<br>   __THROW.  </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> ssize_t send (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> __fd, __const </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">__buf, size_t __n, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> __flags);<br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> Read N bytes into BUF from socket FD.<br>   Returns the number read or -1 for errors.<br><br>   This function is a cancellation point and therefore not marked with<br>   __THROW.  </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> ssize_t recv (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> __fd, </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">__buf, size_t __n, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> __flags);</span></div> q两个函数的W一个参数是用于“通讯”的socketQ第二个参数是发送或者接收数据的起始Ҏ针,W三个参数是数据长度Q第四个参数是控制符P默认属性设|ؓ0可以了Q。失败时候传?1Q否则传回实际发送或者接收数据的大小Q返?往往意味着q接断开了?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"> TcpServer::handleEcho()<br>{<br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> BUFFERSIZE </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> buffer[BUFFERSIZE];<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> recvMsgSize;<br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> goon </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><br>    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( goon </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000"> ) {<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (recvMsgSize </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> recv(communicationSock, buffer, BUFFERSIZE, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)) </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>            </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">recv() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( recvMsgSize </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> ) {<br>            goon </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br>        } </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br>            </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( send(communicationSock, buffer, recvMsgSize, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> recvMsgSize ) {<br>                </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">send() failed</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>            }<br>        }<br>    }<br><br>    close(communicationSock);<br>}</span></div> 本小节最后要讲的函数是close()Q它包含?lt;unistd.h>?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 </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> Close the file descriptor FD.<br><br>   This function is a cancellation point and therefore not marked with<br>   __THROW.  </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">extern</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> close (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> __fd);</span></div> q个函数用于关闭一个文件描q符Q自Ӟ也就可以用于关闭socket?br>下一节是完整的源代码。默认的监听端口?000。我们可以通过<br>$telnet 127.0.0.1 5000<br>验证在本行的echo serverE序?br> <img src ="http://www.shnenglu.com/lf426/aggbug/56279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-07-16 12:26 <a href="http://www.shnenglu.com/lf426/archive/2008/07/16/56279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socket ~程入门教程Q一QTCP server 端:6、创建“通讯 ”嵌套字http://www.shnenglu.com/lf426/archive/2008/07/15/56180.htmllf426lf426Tue, 15 Jul 2008 05:04:00 GMThttp://www.shnenglu.com/lf426/archive/2008/07/15/56180.htmlhttp://www.shnenglu.com/lf426/comments/56180.htmlhttp://www.shnenglu.com/lf426/archive/2008/07/15/56180.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/56180.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/56180.html
        q里?#8220;通讯”加上了引P是因为实际上所有的socket都有通讯的功能,只是在我们的例子中,之前那个socket只负责listenQ而这个socket负责接受信息qecho回去?br> 我们现看看这个函敎ͼ
bool TcpServer::isAccept()
{
    unsigned 
int clntAddrLen = sizeof(clntAddr);

    
if ( (communicationSock = accept(listenSock, (sockaddr*)&clntAddr, &clntAddrLen)) < 0 ) {
        
return false;
    } 
else {
        std::cout 
<< "Client(IP: " << inet_ntoa(clntAddr.sin_addr) << ") connected.\n";
        
return true;
    }
}

用accept()创徏新的socket

        在我们的例子中,communicationSock实际上是用函数accept()创徏的?br>
int accept(int socket, struct sockaddr* clientAddress, unsigned int* addressLength);
在Linux中的实现为:
/* Await a connection on socket FD.
   When a connection arrives, open a new socket to communicate with it,
   set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
   peer and *ADDR_LEN to the address's actual length, and return the
   new socket's descriptor, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  
*/
extern int accept (int __fd, __SOCKADDR_ARG __addr,
           socklen_t 
*__restrict __addr_len);
q个函数实际上v着构造socket作用的仅仅只有第一个参敎ͼ另外q有一个不在这个函数内表现出来的因素,后面会讨论到Q,后面两个指针都有副作用,在socket创徏后,会将客户端sockaddr的数据以及结构体的大传回?br>        当程序调用accept()的时候,E序有可能就停下来等accept()的结果。这是我们前一节说到的blockQ阻塞)。这如同我们调用std::cin的时候系l会{待输入直到回R一栗accept()是一个有可能引vblock的函数。请注意我说的是“有可?#8221;Q这是因为accept()的block与否实际上决定与W一个参数socket的属性。这个文件描q符如果是block的,accept()blockQ否则就不block。默认情况下Qsocket的属性是“可读可写”Qƈ且,是阻塞的。所以,我们不修改socket属性的时候,accept()是阻塞的?br>
accept()的另一面connect()

        accept()只是在server端被动的{待Q它所响应的,是client端connect()函数Q?br>
int connect(int socket, struct sockaddr* foreignAddress, unsigned int addressLength);
虽然我们q里不打详l说明这个client端的函数Q但是我们可以看出来Q这个函C之前我们介绍的bind()有几分相|特别在Linux的实CQ?br>
/* Open a connection on socket FD to peer at ADDR (which LEN bytes long).
   For connectionless socket types, just set the default address to send to
   and the only address from which to accept transmissions.
   Return 0 on success, -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  
*/
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
connect() 也用了const的sockaddrQ只不过是远E电脑上的而非bind()的本机?br>        accept()在server端表面上是通过listen socket创徏了新的socketQ实际上Q这U行为是在接受对方客hE序中connect()函数的请求后发生的。综合v看,被创建的新socket实际上包含了listen socket的信息以及客Lconnect()h中所包含的信息——客L的sockaddr地址?br>
新socket与sockaddr的关p?br>
        accept()创徏的新socketQ我们例子中的communicationSockQ这里我们简单用newSock来带指)首先包含了listen socket的信息,所以,newSockh本机sockaddr的信息;其次Q因为它响应于client端connect()函数的请求,所以,它还包含了clinet端sockaddr的信息?br>        我们说过QstreamŞ式的TCP协议实际上是建立起一?#8220;可来可去”的通道。用于listen的通道Q远E机的目标地址是不定的;但是newSock却是有指定的本机地址和远E机地址Q所以,q个socketQ才是我们真正用于TCP“通讯”的socket?br>
inet_ntoa()
#include <arpa/inet.h>

/* Convert Internet number in IN to ASCII representation.  The return value
   is a pointer to an internal array containing the string.  
*/
extern char *inet_ntoa (struct in_addr __in) __THROW;
        对于q个函数Q我们可以作ZU,IP地址Q由in_addrl构转换为可ȝASCII形式的固定用法?br>


lf426 2008-07-15 13:04 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:5、创建监听嵌套字http://www.shnenglu.com/lf426/archive/2008/07/14/56092.htmllf426lf426Mon, 14 Jul 2008 05:02:00 GMThttp://www.shnenglu.com/lf426/archive/2008/07/14/56092.htmlhttp://www.shnenglu.com/lf426/comments/56092.htmlhttp://www.shnenglu.com/lf426/archive/2008/07/14/56092.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/56092.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/56092.html
        前面一节Q我们已l写ZTcpServer的构造函数。这个函数的实际作用Q就是创Zlisten socketQ监听嵌套字Q。这一节,我们来具体分析这个创建的q程?br>
socket和sockaddr的创建是可以怺独立?br>
        在函CQ我们首先通过socket()pȝ调用创徏了listenSockQ然后通过为结构体赋值的Ҏ具体定义了服务器端的sockaddr。(memset()函数的作用是把某个内存段的空间设定ؓ某|q里是清零。)其他的概念已l在前一节讲完了。这里需要补充的是说明宏定义INADDR_ANY。这里的意思是使用本机所有可用的IP地址。当Ӟ如果你机器绑定了多个IP地址Q你也可以指定用哪一个?br>
数据简易模型(SOCK_STREAMQ?br>
        我们的例子以电话做的比喻Q实际上Qsocket stream模型不完全类似电话,它至有以下q些特点Q?br>1、一U持l性的q接。这点跟电话是类似的Q也可以惌成流动着液体的水。一旦断开Q这U流动就会中断?br>2、数据包的发送实际上是非q箋的。这个世界上有什么事物是真正的线性连l的Q呵呵,扯远了,q貌g个哲学问题。我们仅仅需要知道的是,一个数据包不可能是无限大的Q所以,L一个小数据包一个小数据包这L发送的。这一点,又有点像邮包的传递。这些数据包到达与否Q到辄先后ơ序本n是无法保证的Q即是说Q是IP协议无法保证的。但是stream形式的TCP协议Q在IP之上Q做了一定到辑֒到达序的保证?br>3、传送管道实际上是非闭的。要不干嘛叫“|络”-_-!!!。我们之所以能保证数据包的“定点”传送,完全是依靠每个数据包都自带了目的地址信息?br>        由此可见Q虽然socket和sockaddr可以分别创徏Qƈ无依赖关pR但是在实际使用的时候,一个socket臛_会绑定一个本机的sockaddrQ没有自q“地址信息”Q就不能接受到网l上的数据包Q至在TCP协议里面是这LQ?br>
socket与本机sockaddr的绑?br>
        有时候绑定是pȝ的Q务,特别是当你不需要知道自qIP地址和所使用的端口号的时候。但是,我们现在是徏立服务器Q你必须告诉客户端你的连接信息:IP和Port。所以,我们需要指明IP和PortQ然后进行绑定?br>
int bind(int socket, struct sockaddr* localAddress, unsigned int addressLength);
作ؓC++的程序员Q也怽会觉得这个函数很不友好,它似乎更应该写成Q?br>
int bind_cpp_style(int socket, const sockaddr& localAddress);
我们需要通过函数原型指明两点Q?br>1、我们仅仅用sockaddrl构的数据,但ƈ不会对原有的数据q行修改Q?br>2、我们用的是完整的l构体,而不仅仅是这个结构体的指针。(很显然光用指针是无法说明l构体大的Q?br>q运的是Q在Linux的实CQ这个函数已l被写ؓQ?br>
#include <sys/socket.h>

/* Give the socket FD the local address ADDR (which is LEN bytes long).  */
extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
     __THROW;
看到亲切的constQ我们就知道q个指针带入是没?#8220;副作?#8221;的?br>
监听Qlisten()

        stream模型Ş式上是一U?#8220;持箋?#8221;的连接,q就是要求信息的动?#8220;可来可去”的。也是_stream的socket除了l定本机的sockaddrQ还应该拥有Ҏsockaddr的信息。在listen()中,q?#8220;Ҏ的sockaddr”可以不是某一个特定的sockaddr。实际上Qlisten socket的目的是准备被动的接受来?#8220;所?#8221;sockaddr的请求。所以,listen()反而就不能指定某个特定的sockaddr?br>
int listen(int socket, int queueLimit);
其中W二个参数是{待队列的限Ӟ一般设|在5-20。Linux中实CؓQ?br>
#include <sys/socket.h>

/* Prepare to accept connections on socket FD.
   N connection requests will be queued before further requests are refused.
   Returns 0 on success, -1 for errors.  
*/
extern int listen (int __fd, int __n) __THROW;
完成了这一步,回到我们的例子,像是让你小弟在电话机前做好了接电话的准备工作。需要再ơ强调的是,q些行ؓ仅仅是改变了socket的状态,实际上我惛_调的是,Z么这些函C会造成blockQ阻塞)的原因。(block的概念以后再解释Q?br>


lf426 2008-07-14 13:02 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:4、构造函数涉及的概念http://www.shnenglu.com/lf426/archive/2008/07/12/55956.htmllf426lf426Sat, 12 Jul 2008 05:27:00 GMThttp://www.shnenglu.com/lf426/archive/2008/07/12/55956.htmlhttp://www.shnenglu.com/lf426/comments/55956.htmlhttp://www.shnenglu.com/lf426/archive/2008/07/12/55956.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/55956.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/55956.html
        话题回到“黑社会办公室”的例子,讲概念已l扯得比较远了,不过Q这一节我们还得讲概念Q不q好在有些程序的例子。如果大家不想翻回去看TcpServercȝ原型Q我q里直接l出q个头文件的完整源代码:
//Filename: TcpServerClass.hpp

#ifndef TCPSERVERCLASS_HPP_INCLUDED
#define TCPSERVERCLASS_HPP_INCLUDED

#include 
<unistd.h>
#include 
<iostream>
#include 
<sys/socket.h>
#include 
<arpa/inet.h>

class TcpServer
{
private:
    
int listenSock;
    
int communicationSock;
    sockaddr_in servAddr;
    sockaddr_in clntAddr;
public:
    TcpServer(
int listen_port);
    
bool isAccept();
    
void handleEcho();
};


#endif // TCPSERVERCLASS_HPP_INCLUDED
我们已经解释了ؓ什么listenSock和communicationSock的类型是intQ以及sockaddr_in是什么结构,现在来写q个cȝ构造函敎ͼ
TcpServer::TcpServer(int listen_port)
{
    
if ( (listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
        
throw "socket() failed";
    }

    memset(
&servAddr, 0sizeof(servAddr));
    servAddr.sin_family 
= AF_INET;
    servAddr.sin_addr.s_addr 
= htonl(INADDR_ANY);
    servAddr.sin_port 
= htons(listen_port);

    
if ( bind(listenSock, (sockaddr*)&servAddr, sizeof(servAddr)) < 0 ) {
        
throw "bind() failed";
    }

    
if ( listen(listenSock, 10< 0 ) {
        
throw "listen() failed";
    }
}
好,先看看程序培M下感觉,我们q得说概c?br>
数据装QData EncapsutationQ?br>
        我们前面说到了网l分层:链\——网l——传输——应用。数据从应用E序里诞生,传送到互联|上每一层都会进行一ơ封装:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我们用socket重点描述的是协议Q包括网l协议(IPQ和传输协议QTCP/UDPQ?br>sockaddr重点描述的是地址Q包括IP地址和TCP/UDP端口?br>
socket()函数

    我们从TcpServer::TcpServer()函数可以看到Qsocket和sockaddr的生是可以怺独立的。socket()的函数原型是Q?br>
int socket(int protocolFamily, int type, int protocol);
在Linux中的实现为:
#include <sys/socket.h>

/* Create a new socket of type TYPE in domain DOMAIN, using
   protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
   Returns a file descriptor for the new socket, or -1 for errors.  
*/
extern int socket (int __domain, int __type, int __protocol) __THROW;
W一个参数是协议(Linux里面叫作域,意思一LQ,q是那句话,我们q篇教程用到的就仅仅是一个PF_INETQprotocol family : internetQ,很多时候你会发Ch们也l常在这里赋gؓAF_INETQ事实上Q当前,AF_INET是PF_INET的一?defineQ但是,写成PF_INET从语义上会更加严谨。这也就是TCP/IP协议中的IP协议QInternet ProtocolQ,|络层的协议?br>后面两个参数定义传输层的协议?br>W二个参数是传输层协议类型,我们教程里用到的宏,只有两个QSOCK_STREAMQ数据流格式Q和SOCK_DGRAMQ数据报格式Q;Q具体是什么我们以后讨论)
W三个参数是具体的传输层协议。当赋gؓ0的时候,pȝ会根据传输层协议cd自动匚w和选择。事实上Q当前,匚wSOCK_STREAM的就是TCP协议Q而匹配SOCK_DGRAM是UDP协议。所以,我们指定了第二个参数Q第三个可以简单的讄?。不q,Z严}Q我们最好还是把具体协议写出来,比如Q我们的例子中的TCP协议的宏名称QIPPROTO_TCP?br>
数据?#8220;地址”

        从数据封装的模型Q我们可以看到数据是怎么从应用程序传递到互联|的。我们说q,数据的传送是通过socketq行的。但是socket只描qC协议cd。要让数据正的传送到某个地方Q必L加那个地方的sockaddr地址Q同P要能接受|络上的数据Q必L自己的sockaddr地址?br>        可见Q在|络上传送的数据包,是socket和sockaddr共同“染指”的结果。他们共同封装和指定了一个数据包的网l协议(IPQ和IP地址Q传输协议(TCP/UDPQ和端口受?br>
|络字节和本机字节的怺转换

        sockaddrl构中的IP地址Qsin_addr.s_addrQ和端口Psin_portQ将被封装到|络上传送的数据包中Q所以,它的l构形式需要保证是|络字节形式。我们这里用到的函数是htons()和htonl()Q这些羃写的意思是Q?br>h: hostQ主机(本机Q?br>n: networkQ网l?br>to: to转换
s: shortQ?6位(2字节Q常用于端口P
l: long, 32位(4字节Q常用于IP地址Q?br>“反过?#8221;的函C是存在的ntohs()和ntohl()?br>
动作与持l行?br>
        本节最后的一个概念可以跟计算机无兟뀂作为动词,有些可以描述动作Q有些是描述一重持l的行ؓ状态的Q就如同一般动词和be动词一P。扯到C++来说Q我们可以把持箋行ؓ装到函数内部,只留出动作的接口。事实上Q构造函C的bind()和listen()是q种描述持箋状态的行ؓ函数?br>


lf426 2008-07-12 13:27 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:3、sockaddr与sockaddr_inhttp://www.shnenglu.com/lf426/archive/2008/07/10/55800.htmllf426lf426Thu, 10 Jul 2008 07:14:00 GMThttp://www.shnenglu.com/lf426/archive/2008/07/10/55800.htmlhttp://www.shnenglu.com/lf426/comments/55800.htmlhttp://www.shnenglu.com/lf426/archive/2008/07/10/55800.html#Feedback2http://www.shnenglu.com/lf426/comments/commentRss/55800.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/55800.html
收g人地址

        一家化妆品公司一Ҏ产品的样品,准备发给某学校某个班的女生们免费试用。通常情况下,qg邮包的地址上可以这么写Q?br>
收g人:全体女生?br>地址QA省B市C学校QXUY班?/span>
但是Q如果在描述地址的时候这样写呢:
收g人:全体女生?br>地址Q请打电话xxxxxxxxQ找他们学校一个叫Lucy的女生,然后把东襉K到她的班上?/span>
q种文字是相当的诡异?_-!!!Q但是ƈ不等于就没有表述清楚邮包的去向和地址。事实上邮局看到q样的地址一定会发飙的,然而对于电脑,如果你的地址描述形式是他可以接受和执行的Q他׃老老实实的按你的要求去?#8230;…
        所以,如何描述地址不是问题的关键,关键在于q样的表q是不是能够表述清楚一个地址。一U更加通用的表辑Ş式可能是q样的:
收g人:全体女生?br>地址Q?/span><一U地址描述方式>
        事实上,在socket的通用address描述l构sockaddr中正是用q样的方式来q行地址描述的:
struct sockaddr
{
    unsigned 
short sa_family;
    
char sa_data[14];
};
q是一?6字节大小的结构(2+14Q,sa_family可以认ؓ是socket address family的羃写,也可能被写成AFQAddress FamilyQ,他就好像我们例子中那?#8220;收g人:全体女生”一P虽然事实上有很多AF的种c,但是我们q个教程中只用得上大名鼎鼎的internet家族AF_INET。另外的14字节是用来描q地址的。这是一U通用l构Q事实上Q当我们指定sa_family=AF_INET之后Qsa_data的Ş式也p固定了下来:最前端?字节用于记录16位的端口Q紧接着?字节用于记录32位的IP地址Q最后的8字节清空为零。这是我们实际在构造sockaddr时候用到的l构sockaddr_inQ意指socket address internetQ:
struct sockaddr_in
{
    unsigned 
short sin_family;
    unsigned 
short sin_port;
    
struct in_addr sin_addr;
    
char sin_zero[8];
};
我想Qsin_的意思,是socket (address) internet吧,只不q把address省略掉了。sin_addr被定义成了一个结构,q个l构实际上就是:
struct in_addr
{
    unsigned 
long s_addr;
};
in_addr昄是internet address了,s_addr是什么意思呢Q说实话我没猜出值得肯定的答案(Ҏ下面|友的评论,其意思ؓsource addressQ谢谢)Q也许就是socket address的意思吧Q尽跟更广义的sockaddrl构意思有所重复了。哎Q这些都是历史原因,也许我是没有_֊去考究了?br>
sockaddr和sockaddr_in在Linux中的实现

        你可能还记得我之前说q,UNIX和Linux上的socket实现都是从BSD的socket实现演变q来的。事实上Qsocketq个词本来的意思,是Berkeley Socket interface的简单说法。Linux上的socket与原本的socket的应该是完全兼容的,不过发展C天,在代码实C可能有些的差别。我们就Ҏ求疵的来看看q些区别在什么地斏V?br>
#include <bits/socket.h>

/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    
/* Common data: address family and length.  */
    
char sa_data[14];        /* Address data.  */
  };

//==============

/* POSIX.1g specifies this type name for the `sa_family' member.  */
typedef unsigned 
short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  
*/

#define    __SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

#define __SOCKADDR_COMMON_SIZE    (sizeof (unsigned short int))
可以看到Q{了几ơtypedefQ几ơ宏定义Q实际效果是与标准socket一L?br>
#include <netinet/in.h>

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };

//=================

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;            
/* Port number.  */
    
struct in_addr sin_addr;        /* Internet address.  */

    
/* Pad to size of `struct sockaddr'.  */
    unsigned 
char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE 
-
               
sizeof (in_port_t) -
               
sizeof (struct in_addr)];
  };
同样的,看v来挺复杂Q实际上与标准socket的定义是一L?br>
头文件依赖关p?br>        <bits/socket.h>是包含在<sys/socket.h>中的Q?lt;netinet/in.h>是包含在<arpa/inet.h>中的Q实际上我们在程序中往往是Q?br>
#include <sys/socket.h>
#include 
<arpa/inet.h>
值得知道的是QARPA?Advanced research project agencyQ美国国防部高研究计划暑)的所写,ARPANET是当今互联网的前w,所以我们就可以惌Qؓ什么inet.h会在arpa目录下了?br>

lf426 2008-07-10 15:14 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:2、socket与文件描q符http://www.shnenglu.com/lf426/archive/2008/07/10/55771.htmllf426lf426Wed, 09 Jul 2008 18:42:00 GMThttp://www.shnenglu.com/lf426/archive/2008/07/10/55771.htmlhttp://www.shnenglu.com/lf426/comments/55771.htmlhttp://www.shnenglu.com/lf426/archive/2008/07/10/55771.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/55771.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/55771.html
UNIX中的一切事物都是文Ӟeverything in Unix is a file!Q?br>
        当我在这教E中提到UNIX的时候,其意思专指符合UNIX标准的所?#8220;正统”UNIX的衍生系l(其实我就用来带指那些C最初UNIX源代码的商业pȝQ操作系l和cMLinuxQBSDq些cUNIXpȝ。如果某些要ҎLinuxҎ的,或者因为本人孤陋寡L时搞不清楚是LinuxҎ的还是UNIX通用的,我就会指明是LinuxQ甚臛_发行版(我本人在写这教E的时候是以Debian GNU/Linux 4.0 etch为测试^台的Q?br>        我们学习UNIX的时候,恐怕听到的W一句话是q句QUNIX中一切都是文件。这是UNIX的基本理念之一Q也是一句很好的概括。比如,很多UNIX老鸟会DZ例子来,“你看Q?dev/hdc是个文gQ它实际上也是我的光?#8230;…”UNIX中的文g可以是:|络q接Qnetwork connectionQ,输入输出QFIFOQ,道Qa pipeQ,l端QterminalQ,盘上的实际文gQ或者其它Q何东东?br>
文g与文件描q符Qfile & file descriptorQ?br>
        你可能对上一章中建模cM的intq记忆犹新。我们用int在描qsocketQ实际上Q所有的文g描述W都是intQ没错,用的是一个整数类型。如果你觉得q样让你很难接受Q那么恭喜你Q你跟我一P也许是深中C++面向对象思想的毒了^^。因为是intQ所以文件描q符不可能是C++概念中的对象Q因为int无法发出行ؓQ但是,qƈ不代表也不能接受一个动作哈?br>        PASCAL之父在批判面向对象思想教条的时候,曄生动的D了个例子Q?#8220;在OOP的概念中Q绝对不应该接受a+bq种表达的, OOP对这个问题的表达应该是a.add(b)”。fdQfile descriptorQ可以作为接受动作的对象Q但是本w却无法发出动作Q这如同一个只能做宾语不能做主语的名词Q是个不完整的对象。但是,请别忘了Linux和socket本n是C语言的物,我们必须接受在面向过E时代下的物,正视历史——当Ӟq与我们自己再进行OOP的封装ƈ不矛盾?br>        我们应该C3个已l打开的fdQ?Q标准输入(STDIN_FILENOQ;1Q标准输出(STDOUT_FILENOQ;2Q标准错误(STDERR_FILENOQ。(以上宏定义在<unistd.h>中)一个最单的使用fd的例子,是使用<unistd.h>中的函数Qwrite(1, "Hello, World!\n", 20);Q在标准输出上显C?#8220;Hello, World!”?br>        另外一个需要注意的问题是,file和fdq一定是一一对应的。当一个file被多个程序调用的时候,会生成相互独立的fd。这个概念可以类比于C++中的引用Qeg: int& rTmp = tmp;Q?br>
socket与file descriptor

        文g是应用程序与pȝQ包括特定硬件设备)之间的桥梁,而文件描q符是应用E序使用q个“桥梁”的接口。在需要的时候,应用E序会向pȝ甌一个文Ӟ然后文件的描述W返回供E序使用。返回socket的文仉常被创建在/tmp或?usr/tmp中。我们实际上不用兛_q些文gQ仅仅能够利用返回的socket描述W就可以了?br>       好了Q说了这么多Q实际上p释了一个问题,“Z么socket的类型是intQ?#8221; -_-!!!



lf426 2008-07-10 02:42 发表评论
]]>
socket ~程入门教程Q一QTCP server 端:1、徏?/title><link>http://www.shnenglu.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.shnenglu.com/lf426/archive/2008/07/08/55641.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/55641.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/07/08/55641.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/55641.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/55641.html</trackback:ping><description><![CDATA[作者:龙飞<br><br>        l大部分关于socket~程的教EL从socket的概念开始讲L。要知道Qsocket的初h个庞大的体系QTCP/IP只是q个庞大体系下一个很的子集Q而我们真正能用上的更是这个子集中的一部分:q输层(Host-to-Host Transport LayerQ的TCP和UDP协议Q以及用这两个协议q行应用层(Application LayerQ的开发。即使是socket的核心部分,|络层(Internet LayerQ的IP协议Q在~程的时候我们也很少会感觉到它的存在——因为已l被装好了Q我们唯一需要做的事情就是传入一个宏。第一节我想介l的概念p么多Q当Ӟ既然我们已经说了3个层了,我想最好还是把最后一个层也说出来Q即所谓链路层QNetwork Access LayerQ,它包括了物理g和驱动程序。这四个层从底到高的序是:链\层-Q网l层Q-q输层-Q应用层?br>        好,说实话我们现在ƈ不清楚所谓TCP到底是什么东东,不过我们知道q东东名气很大。或怽早就知道Q另外一个声名狼藉徏立在TCP协议基础上的应用E序Q它曄几乎是统M一个时代,即是今天,我们依然无法消除他的影响力的——恩Q是的,是telnet?br>        在这个教E中Q我使用的环境是Debian GNU/Linux 4.0 etch。传说中的stable -_-!!!Q恩Q我是很保守的h。如果你不是自己DIY出来的系l,怿默认安装里面应该有telnetQ?usr/bin/telnetQ要是没装就自己aptitude install吧)。telnet可以与所有遵循TCP协议的服务器端进行通讯。通常Qsocket~程LClient/Server形式的,因ؓ有了telnetQ我们可以先不考虑client的程序,我们先写一个支持TCP协议的server端,然后用telnet作ؓclient验证我们的程序就好了?br>        server端的功能Q我们也考虑一U最单的反馈形式Qecho。就如同你在l端输入echo 'Hello World'Q回车后shell׃l你q回Hello World一P我们的第一个TCP serverq以实现这个功能?br>        什么样的模型适合描述q样的一Userver呢?我相信,一个很2的例子会有助于我们记忆TCP server端的基本程?br>        惌你自己是个小大{Q坐办公室(什么样的黑C会做办公室啊?可能是讨债公司吧^^Q你很土Q只有一个小弟帮你接电话Q因Z自己的号码是不敢对外公开的)。一ơ通讯的流E大概应该是q样的:弟那里的L电话响了Q小弟接L话;Ҏ说是你女朋友A妹;弟转达_“老大Q你马子电话”Q你_接过来;弟把电话接l你Q你和你x友聊天半时Q挂电话?br>        我们来分析一下整个过E中的元素。先分析成员数据Q请注意Q这里开始用C++术语了)Q你弟QlistenSockQ,你需要他来监听(listenQ这是socket~程中的术语Q电话;你自己(communicationSockQ,实际上打电话q行交流的是你自己;你的电话LQservAddrQ,否则你女朋友怎么能找CQ你x友的电话LQclntAddrQ,q个比喻有点牵强Q因Z实上你接L话,不需要知道对方的L也可以通话Q虽然事实上你应该是知道的,你不会取消了来电昄功能吧^^Q,但是Q难道你是只接女朋友电话从来不打q去的牛人吗Q这个过E中的行为(成员函数Q:你小弟接电话q{接给你(isAccept()Q;你自q通话QhandleEcho()Q(q个行ؓ实比较土,只会乌鸦学舌的echoQ呵呵)?br>        单的_是q些了。根据这个模型,我们可以很容易写出实现我们需要的echo功能的TCP server的类Q?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"> TcpServer<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> listenSock;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> communicationSock;<br>    sockaddr_in servAddr;<br>    sockaddr_in clntAddr;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    TcpServer(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> listen_port);<br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> isAccept();<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> handleEcho();<br>};</span></div> q里面有些简写,比如Qsock实际上就是socketQaddr是address。serv和clnt我想你一定能猜到是server和client吧。还有一个socket中的l构体sockaddr_inQ实际上是q个意思:socket address internetQ网l嵌套字地址Q,具体解说Q请看下回分解?br><br> <img src ="http://www.shnenglu.com/lf426/aggbug/55641.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-07-08 15:42 <a href="http://www.shnenglu.com/lf426/archive/2008/07/08/55641.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Code::Blocks在Debian下的l色安装http://www.shnenglu.com/lf426/archive/2008/06/25/54572.htmllf426lf426Wed, 25 Jun 2008 09:46:00 GMThttp://www.shnenglu.com/lf426/archive/2008/06/25/54572.htmlhttp://www.shnenglu.com/lf426/comments/54572.htmlhttp://www.shnenglu.com/lf426/archive/2008/06/25/54572.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/54572.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/54572.html短描q?
媲美于VC的C++ IDE集成开发环境,h较完善的自动补全功能。基于官方的Debian 8.02最新版本。已包含libwx2.8。(Debian etch源上的是2.6Q。无root权限安装Q解压即可用?br>

安装步骤:
解压到自己安排的位置。cd到相关目录,q行sh脚本setup.sh可以了。将生成sh脚本codeblocksQ可直接通过该脚本启动。(实际上就是设|了LD_LIBRARY_PATH和CODEBLOCKS_DATA_DIRQ?/div>
下蝲地址Q?br>http://www.fs2you.com/zh-cn/files/7de0ba0c-428f-11dd-812f-00142218fc6e/

下面介绍自己q行l色安装的过E?br>首先到Code::Blocks的项目页下蝲最新的版本8.02?br>http://www.codeblocks.org/
当然Q我用的是DebianQ下载的是q个版本Qcodeblocks-8.02debian-i386.tar.gz?br>解压后是一堆deb包,心的把q些包解压到某个位置下的usr目录下。(注意Q不是默认的/usr目录Q。然后这个文件夹的名字不重要Q是可以更换的。比如,我就换成了codeblocks。这时候,q个目录下应该有q些文g夹:bin, include, lib, share。其中,可执行文件在bin目录下。cd到bin目录下,查codeblocks的依赖库及其路径Q?br>
ldd codeblocks
然后可以看到一大堆没有扑ֈ的soQ?br>
        linux-gate.so.1 =>  (0xffffe000)
        libgtk
-x11-2.0.so.0 => /usr/lib/libgtk-x11-2.0.so.0 (0xb7ca1000)
        libgdk
-x11-2.0.so.0 => /usr/lib/libgdk-x11-2.0.so.0 (0xb7c20000)
        libatk
-1.0.so.0 => /usr/lib/libatk-1.0.so.0 (0xb7c06000)
        libgdk_pixbuf
-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0xb7bf0000)
        libpangocairo
-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0xb7be8000)
        libXext.so.
6 => /usr/lib/libXext.so.6 (0xb7bd9000)
        libXinerama.so.
1 => /usr/lib/libXinerama.so.1 (0xb7bd6000)
        libXi.so.
6 => /usr/lib/libXi.so.6 (0xb7bce000)
        libXrandr.so.
2 => /usr/lib/libXrandr.so.2 (0xb7bcb000)
        libXcursor.so.
1 => /usr/lib/libXcursor.so.1 (0xb7bc2000)
        libXfixes.so.
3 => /usr/lib/libXfixes.so.3 (0xb7bbd000)
        libpango
-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0xb7b82000)
        libcairo.so.
2 => /usr/lib/libcairo.so.2 (0xb7b20000)
        libfreetype.so.
6 => /usr/lib/libfreetype.so.6 (0xb7ab6000)
        libz.so.
1 => /usr/lib/libz.so.1 (0xb7aa2000)
        libfontconfig.so.
1 => /usr/lib/libfontconfig.so.1 (0xb7a77000)
        libpng12.so.
0 => /usr/lib/libpng12.so.0 (0xb7a54000)
        libXrender.so.
1 => /usr/lib/libXrender.so.1 (0xb7a4b000)
        libX11.so.
6 => /usr/lib/libX11.so.6 (0xb795f000)
        libgobject
-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0xb7925000)
        libgmodule
-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0xb7922000)
        libglib
-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0xb7890000)
        librt.so.
1 => /lib/tls/i686/cmov/librt.so.1 (0xb7887000)
        libcodeblocks.so.
0 => not found
        libwx_gtk2u_richtext
-2.8.so.0 => not found
        libwx_gtk2u_aui
-2.8.so.0 => not found
        libwx_gtk2u_xrc
-2.8.so.0 => not found
        libwx_gtk2u_qa
-2.8.so.0 => not found
        libwx_gtk2u_html
-2.8.so.0 => not found
        libwx_gtk2u_adv
-2.8.so.0 => not found
        libwx_gtk2u_core
-2.8.so.0 => not found
        libwx_baseu_xml
-2.8.so.0 => not found
        libwx_baseu_net
-2.8.so.0 => not found
        libwx_baseu
-2.8.so.0 => not found
        libpthread.so.
0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7872000)
        libdl.so.
2 => /lib/tls/i686/cmov/libdl.so.2 (0xb786e000)
        libstdc
++.so.6 => /usr/lib/libstdc++.so.6 (0xb7789000)
        libm.so.
6 => /lib/tls/i686/cmov/libm.so.6 (0xb7764000)
        libgcc_s.so.
1 => /lib/libgcc_s.so.1 (0xb7759000)
        libc.so.
6 => /lib/tls/i686/cmov/libc.so.6 (0xb7627000)
        libpangoft2
-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0xb75fc000)
        libXau.so.
6 => /usr/lib/libXau.so.6 (0xb75f9000)
        libexpat.so.
1 => /usr/lib/libexpat.so.1 (0xb75d9000)
        libXdmcp.so.
6 => /usr/lib/libXdmcp.so.6 (0xb75d3000)
        
/lib/ld-linux.so.2 (0xb7f9c000)
其中libcodeblocks.so.0是Code::Blocks自带的,已经在lib目录下了Q应为我们没有指定LD_LABRARY_PATH路径而找不到?br>其它库是属于libwx的。在源中搜烦一下:
aptitude search libwx
很不q,源里面只?.4?.6版本的。所以,我们只好去wx官方M?.8的库?br>http://www.wxwidgets.org/
我们在:
http://apt.wxwidgets.org/dists/etch-wx/main/binary-i386/
下找到我们需要的׃n库文Ӟ
libwxbase2.8-0_2.8.7.1-0_i386.deb ?libwxgtk2.8-0_2.8.7.1-0_i386.deb 
Q真快,今天已经更新2.8.8.0?_-!!!应该也没问题Q不q我没试Q?br>把解压出来的so和s-link都放到codeblocks/lib/文g夹下面。最后,我们讄LD_LABRARY_PATH可以了?br>可以直接用这个脚本设|:
#!/bin/sh

echo 
"#!/bin/sh" > codeblocks
echo 
"LD_LIBRARY_PATH=$PWD/lib CODEBLOCKS_DATA_DIR=$PWD $PWD/bin/codeblocks" >> codeblocks
chmod 
+x codeblocks
生成的启动脚本应该类DPQ?PWD表示当前目录Q也是codeblocks所在的位置。)
#!/bin/sh
LD_LIBRARY_PATH
=/home/lf426/app/code/codeblocks/lib CODEBLOCKS_DATA_DIR=/home/lf426/app/code/codeblocks /home/lf426/app/code/codeblocks/bin/codeblocks
通过q个脚本可以启动Code::Blocks了。整个过E不需要root权限哦(你不会想当root敢死队吧。^^Q?br>


lf426 2008-06-25 17:46 发表评论
]]>Linux下C++ IDE的选择?/title><link>http://www.shnenglu.com/lf426/archive/2008/06/25/54564.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Wed, 25 Jun 2008 08:45:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2008/06/25/54564.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/54564.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/06/25/54564.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/54564.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/54564.html</trackback:ping><description><![CDATA[        SF被封了!NNDQ本来还说申请了个项目页Q大家可以更Ҏ的下载源代码的,现在又恶心了。只有用代理了。Code::Blocks目也是在SF上的Q昨天晚上还好好的。好在这个项目在德国某个|站q有个镜像,大家应该能下得到的?br>        Linux下的C++IDE环境一直是一个缠人的问题。当Ӟ很多黑客告诉我们vim矣Q可是我们毕竟还是很难以C那么多函数。我惻Iwin32 API实更难以记忆吧Q所以M$搞出个VCq样的好东东QLinux下的牛h们都是从70q代开始玩C的hQ他们多多少更习惯C而不是C++Q包括Linus本hq跟BS老大打过口水战。所以,vim对于他们Q对于CQ可能已l相当够用了——但是,我们是凡人,我们q是希望有个自动补全功能比较强,也不用每ơ都自己写Makefile的IDE?br>        其实一开始关注的是AnjutaQ因是号UGnome下的原生品,可惜啊,功能实在是太一般般了,都还不如用vim加各U插件呢。后来又试了<a title="eclipse" >eclipse</a> 比AnjutaZ不少Q这个项目好像是得到哪个大公司资助了Q搞得很华丽的样子。可是,ZJavaQ速度q是慢啊。另外,逼着我装JVM也让我比较不爽。当前Linux下大有Python淘汰Java的趋ѝKDevelop听说是不错,可是我还没开始用KDEQ貌似非原生品,怕麻烦,忍了?br>        昨天在论坛上看到大家讨论codeblocksQ之前在Windows下关注过Q后来传闻说不再l护了,没攑֜心上。传L竟是传闻Q昨天到codeblocks目上看了下,最新的更新是在今年2月底呵,有够新的。估计是之前周期太长了吧。慢功出l活Q本着对d国h认真态度的敬佩,下蝲下来试了一下——果Ӟ比eclipse要快很多啊。哈哈,虽然跟VCq是有差距,不过也算是用h比较舒心的IDE了。所以推荐给大家。下文章,我来讲讲在Debian 4.0 ecth下的l色安装Ҏ?br><img src ="http://www.shnenglu.com/lf426/aggbug/54564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-06-25 16:45 <a href="http://www.shnenglu.com/lf426/archive/2008/06/25/54564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>构徏vim的可视化C++~辑q_http://www.shnenglu.com/lf426/archive/2008/05/27/51300.htmllf426lf426Tue, 27 May 2008 09:29:00 GMThttp://www.shnenglu.com/lf426/archive/2008/05/27/51300.htmlhttp://www.shnenglu.com/lf426/comments/51300.htmlhttp://www.shnenglu.com/lf426/archive/2008/05/27/51300.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/51300.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/51300.html        Vim的配|文仉常在~/.vimrc中。我们首先可以加入这样两句:
syntax on            //语法高亮打开Q这h们就可以看倒C/C++的关键字成ؓ了彩Ԍ
:set cin!               //C~进打开Q这样vim会自动判断羃q的讄Q?br>        完成q样的设|后Q当我们创徏或者打开vim所能识别的C/C++源文件的时候,我们可以看到关键字的颜色以及自动的~进了?br>        需要指出的一ҎQ按照Unix源程序的习惯Q我们最好以ASCII~码来写E序Q而Debian的内部编码默认是UTF-8。当Ӟ如果我们vim创徏的文件没有汉字等其他字符的时候,产生的文件自动是ASCII~码的,但是Q某些插Ӟ比如vim的c-support插g会自动添加文件的创徏日期Q这P因ؓ我们pȝ默认语言一般是zh_CNQ所以就会生中文的日期昄。所以,一个解x法是在运行创建cpp文g的vim的时候,指定使用的语aQ或者,q脆做一个alias来简单用:
alias cvim='LC_ALL=C vim'
q样Q就可以保创徏的cpp文g不带非ASCII字符?br>
        接下来,我们单了解一下ctags。简单说Qctags是ؓ许多计算a的源代码文g做烦引,以提供给~辑器(比如我们的vimQ用的。我们先看看ctags的帮助:
ctags --help
以下信息是我们将用到的:
-R   Equivalent to --recurse.
--recurse=[yes|no]    Recurse into directories supplied on command line [no].
--languages=[+|-]list
       Restrict files scanned for tags to those mapped to langauges
       specified in the comma-separated 'list'. The list can contain any
       built-in or user-defined language [all].
--fields=[+|-]flags
      Include selected extension fields (flags: "afmikKlnsStz") [fks].
--extra=[+|-]flags
      Include extra tag entries for selected information (flags: "fq").
我们用这L命o在源文g所在的目录q行Q(用样Q我们可以做一个aliasQ我们最后来讨论q个问题Q?br>ctags -R --c++-kinds=+p --fields=+iaS --extra=+q
其中参数的含义是Q?a title="原文出处" >原文出处
--c++-kinds=+p  : 为C++文g增加函数原型的标{?br>--fields=+iaS   : 在标{文件中加入l承信息(i)、类成员的访问控制信?a)、以及函数的指纹(S)
--extra=+q      : 为标{֢加类修饰W。注意,如果没有此选项Q将不能对类成员补全

        好了Q现在准备知识讲完了。我们先实现C++对象?或?>调用Ҏ的时候自动生选择的下拉菜单。我们需要的插g是OmniCppCompleteQ在vim官方q里下蝲Q?br>http://www.vim.org/scripts/script.php?script_id=1520
下蝲到的是一个压~包Q解压到~/.vim/下相应的目录可以了。另外,我们需要在~/.vimrc中打开装蝲插gQ?br>:filetype plugin on
Q或许还需要打开vimҎ代码的识别,不过我是没有用到QDebian 4.0Q如果需要的话,再加?filetype indent onQ?br>另外Q我们关闭vim默认的预览窗口:
:set completeopt=longest,menu
        q样Q当我们创徏了对象,?或?>的时候,׃自动调出cL法的选择H口了?br>
        另外一个常见的补全是对函数的补全,也有现成的插件可以用code_completeQ?br>http://www.vim.org/scripts/script.php?script_id=1764
q个安装更单了Q直接把code_complete.vim拯到~/.vim/plugin/下面可以了?br>插g的用方法是Q当写完一个函敎ͼq打上左括号(之后Q按tab键就可以看倒函数参数列表了Q包括重载的函数?br>
        最后,我们不希望记那么多参敎ͼ希望使用h单一些,我们只需要在bashq行的时候申明我们的两个alias可以了。在~/.bashrc中添加:
alias vctags='ctags -R --c++-kinds=+p --fields=+iaS --extra=+q'
alias cvim='LC_ALL=C vim'
关闭l端后重启动Q可以用type查看我们的新命o已经生效了:
lf426@fleet:~$ type vctags
vctags is aliased to `ctags -R --c++-kinds=+p --fields=+iaS --extra=+q'





lf426 2008-05-27 17:29 发表评论
]]>
þWWW˳һƬ| þ99ƷۺϹҳ| Ʒþþþþ| þۺ϶| þֻоƷҳ| ɫAVԾþþþþ| ޹һɾþþƷۺ| TOKYOۺϾþþƷ| vaĻþò| 99þerֻоƷ18| þþƷ| þòþüƵ7| þݺҹҹavapp| ƷһþþƷɬ| ƷŮþþ| ɫۺϾþ| þ99ƷþþþþҰ| Ʒһþ㽶߿| ŷ޾þþþƷ| þۺ˿ձ| þҹ³Ƭ| ޹˾þþƷ99| þùƷ99þþþþ| 뾫Ʒþþɫ| ޾ƷþþþĻһڣ | bƷþþþþþ| þþ뾫ƷպĦ| ޹պŷۺϾþ| LƷþ| Ʒþþþ9999| ƷŮٸAVѾþ| һAvëƬþþƷ| ݺɫۺϾþȥ | һaƬþëƬ| ľƷþþþ޲| ҹþAAAAAëƬѿ | ͵þþþƷר| þþþAVƬ| ɫۺϾþ߹ۿ| ޹Ʒþ| ѾƷþþþþĻ|