<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    MDA之路

    MDA,UML,XML,Eclipse及Java相關(guān)的Blog
    posts - 53, comments - 494, trackbacks - 0, articles - 2
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
     

    例子代碼就在我的博客中,包括六個(gè)UDPTCP發(fā)送接受的cpp文件,一個(gè)基于MFC的局域網(wǎng)聊天小工具工程,和此小工具的所有運(yùn)行時(shí)庫(kù)、資源和執(zhí)行程序。代碼的壓縮包位置是http://m.tkk7.com/Files/wxb_nudt/socket_src.rar。

    1         前言

    在一些常用的編程技術(shù)中,Socket網(wǎng)絡(luò)編程可以說(shuō)是最簡(jiǎn)單的一種。而且Socket編程需要的基礎(chǔ)知識(shí)很少,適合初學(xué)者學(xué)習(xí)網(wǎng)絡(luò)編程。目前支持網(wǎng)絡(luò)傳輸?shù)募夹g(shù)、語(yǔ)言和工具繁多,但是大部分都是基于Socket開(kāi)發(fā)的,雖說(shuō)這些“高級(jí)”的網(wǎng)絡(luò)技術(shù)屏蔽了大部分底層實(shí)現(xiàn),號(hào)稱(chēng)能極大程度的簡(jiǎn)化開(kāi)發(fā),而事實(shí)上如果你沒(méi)有一點(diǎn)Socket基礎(chǔ),要理解和應(yīng)用這些技術(shù)還是很困難的,而且會(huì)讓你成為“半瓢水”。

    深有感觸的是當(dāng)年我學(xué)習(xí)CORBA的時(shí)候,由于當(dāng)時(shí)各方面的基礎(chǔ)薄弱,整整啃了半年書(shū),最終還是一頭霧水。如果現(xiàn)在讓我?guī)б粋€(gè)人學(xué)CORBA,我一定會(huì)安排好順序:首先弄清C++語(yǔ)法;然后是VC編譯環(huán)境或者nmake的用法;接下來(lái)學(xué)習(xí)一些網(wǎng)絡(luò)基礎(chǔ)知識(shí);然后是Socket編程;這些大概要花費(fèi)3、4個(gè)月。有了這些基礎(chǔ)學(xué)習(xí)CORBA一周即可弄懂,兩個(gè)月就可以基于CORBA進(jìn)行開(kāi)發(fā)了。

    好了,說(shuō)了半天其實(shí)中心思想就一個(gè),Socket很簡(jiǎn)單,很好學(xué)!如果你會(huì)C++或者JAVA,又懂一點(diǎn)點(diǎn)網(wǎng)絡(luò)基礎(chǔ)如TCPUDP的機(jī)制,那么你看完本文就可以熟練進(jìn)行Socket開(kāi)發(fā)了。

    2         Socket簡(jiǎn)介(全文摘抄)

    (本節(jié)內(nèi)容全部抄自網(wǎng)絡(luò),不保證正確性,有興趣的可以看看!)

    80年代初,美國(guó)政府的高級(jí)研究工程機(jī)構(gòu)(ARPA)給加利福尼亞大學(xué)Berkeley分校提供了資金,讓他們?cè)?/span>UNIX操作系統(tǒng)下實(shí)現(xiàn)TCP/IP協(xié)議。在這個(gè)項(xiàng)目中,研究人員為TCP/IP網(wǎng)絡(luò)通信開(kāi)發(fā)了一個(gè)API(應(yīng)用程序接口)。這個(gè)API稱(chēng)為Socket接口(套接字)。今天,SOCKET接口是TCP/IP網(wǎng)絡(luò)最為通用的API,也是在INTERNET上進(jìn)行應(yīng)用開(kāi)發(fā)最為通用的API

    90年代初,由Microsoft聯(lián)合了其他幾家公司共同制定了一套WINDOWS下的網(wǎng)絡(luò)編程接口,即WindowsSockets規(guī)范。它是BerkeleySockets的重要擴(kuò)充,主要是增加了一些異步函數(shù),并增加了符合Windows消息驅(qū)動(dòng)特性的網(wǎng)絡(luò)事件異步選擇機(jī)制。WINDOWSSOCKETS規(guī)范是一套開(kāi)放的、支持多種協(xié)議的Windows下的網(wǎng)絡(luò)編程接口。從1991年的1.0版到1995年的2.0.8版,經(jīng)過(guò)不斷完善并在IntelMicrosoftSun、SGI、Informix、Novell等公司的全力支持下,已成為Windows網(wǎng)絡(luò)編程的事實(shí)上的標(biāo)準(zhǔn)。目前,在實(shí)際應(yīng)用中的WINDOWSSOKCETS規(guī)范主要有1.1版和2.0版。兩者的最重要區(qū)別是1.1版只支持TCP/IP協(xié)議,而2.0版可以支持多協(xié)議。2.0版有良好的向后兼容性,任何使用1.1版的源代碼,二進(jìn)制文件,應(yīng)用程序都可以不加修改地在2.0規(guī)范下使用。

    SOCKET實(shí)際在計(jì)算機(jī)中提供了一個(gè)通信端口,可以通過(guò)這個(gè)端口與任何一個(gè)具有SOCKET接口的計(jì)算機(jī)通信。應(yīng)用程序在網(wǎng)絡(luò)上傳輸,接收的信息都通過(guò)這個(gè)SOCKET接口來(lái)實(shí)現(xiàn)。在應(yīng)用開(kāi)發(fā)中就像使用文件句柄一樣,可以對(duì)SOCKET句柄進(jìn)行讀,寫(xiě)操作。

    3         再說(shuō)兩句

    網(wǎng)上很多文章對(duì)于Socket的來(lái)龍去脈有如教科書(shū)一般的精準(zhǔn)。但是涉及具體編程技術(shù)就往往被VC等集成開(kāi)發(fā)環(huán)境所毒害了,把Windows SDK、MFCSocket、多線程、DLL以及編譯鏈接等等技術(shù)攪合在一起煮成一鍋夾生飯。

    既然要學(xué)習(xí)Socket,就應(yīng)該用最簡(jiǎn)單直白的方式把Socket的幾個(gè)使用要點(diǎn)講出來(lái)。我認(rèn)為程序員最關(guān)心的有以下幾點(diǎn),按照優(yōu)先級(jí)排列如下:

    1.         Socket的機(jī)制是什么?

    2.         C/C++寫(xiě)Socket需要什么頭文件、庫(kù)文件、DLL,它們可以由誰(shuí)提供,安裝后一般處于系統(tǒng)的哪個(gè)文件夾內(nèi)?

    3.         編寫(xiě)Socket程序需要的編程基礎(chǔ)是什么?

    4.         Socket庫(kù)內(nèi)最重要的幾個(gè)函數(shù)和數(shù)據(jù)類(lèi)型是什么?

    5.         兩個(gè)最簡(jiǎn)單的例子程序;

    6.         一個(gè)貼近應(yīng)用的稍微復(fù)雜的Socket應(yīng)用程序。

    我將一一講述這些要點(diǎn),并給出從簡(jiǎn)到繁,從樸素到花哨的所有源代碼以及編譯鏈接的命令。

    4         Socket的機(jī)制是什么?

    我們可以簡(jiǎn)單的把Socket理解為一個(gè)可以連通網(wǎng)絡(luò)上不同計(jì)算機(jī)程序之間的管道,把一堆數(shù)據(jù)從管道的A端扔進(jìn)去,則會(huì)從管道的B端(也許同時(shí)還可以從CD、EF……端冒出來(lái))。管道的端口由兩個(gè)因素來(lái)唯一確認(rèn),即機(jī)器的IP地址和程序所使用的端口號(hào)。IP地址的含義所有人都知道,所謂端口號(hào)就是程序員指定的一個(gè)數(shù)字,許多著名的木馬程序成天在網(wǎng)絡(luò)上掃描不同的端口號(hào)就是為了獲取一個(gè)可以連通的端口從而進(jìn)行破壞。比較著名的端口號(hào)有http80端口和ftp21端口(我記錯(cuò)了么?)。當(dāng)然,建議大家自己寫(xiě)程序不要使用太小的端口號(hào),它們一般被系統(tǒng)占用了,也不要使用一些著名的端口,一般來(lái)說(shuō)使用1000~5000之內(nèi)的端口比較好。

    Socket可以支持?jǐn)?shù)據(jù)的發(fā)送和接收,它會(huì)定義一種稱(chēng)為套接字的變量,發(fā)送數(shù)據(jù)時(shí)首先創(chuàng)建套接字,然后使用該套接字的sendto等方法對(duì)準(zhǔn)某個(gè)IP/端口進(jìn)行數(shù)據(jù)發(fā)送;接收端也首先創(chuàng)建套接字,然后將該套接字綁定到一個(gè)IP/端口上,所有發(fā)向此端口的數(shù)據(jù)會(huì)被該套接字的recv等函數(shù)讀出。如同讀出文件中的數(shù)據(jù)一樣。

    5         所需的頭文件、庫(kù)文件和DLL

    對(duì)于目前使用最廣泛的Windows Socket2.0版本,所需的一些文件如下(以安裝了VC6為例說(shuō)明其物理位置):

    l         頭文件winsock2.h,通常處于C:"Program Files"Microsoft Visual Studio"VC98"INCLUDE;查看該頭文件可知其中又包含了windows.hpshpack4.h頭文件,因此在windows中的一些常用API都可以使用;

    l         庫(kù)文件Ws2_32.lib,通常處于C:"Program Files"Microsoft Visual Studio"VC98"Lib;

    l         DLL文件Ws2_32.dll,通常處于C:"WINDOWS"system32,這個(gè)是可以猜到的。

    6         編寫(xiě)Socket程序需要的編程基礎(chǔ)

    在開(kāi)始編寫(xiě)Socket程序之前,需要以下編程基礎(chǔ):

    l         C++語(yǔ)法;

    l         一點(diǎn)點(diǎn)windows SDK的基礎(chǔ),了解一些SDK的數(shù)據(jù)類(lèi)型與API的調(diào)用方式;

    l         一點(diǎn)點(diǎn)編譯、鏈接和執(zhí)行的技術(shù);知道cllink的最常用用法即可。

    7         UDP

    用最通俗的話講,所謂UDP,就是發(fā)送出去就不管的一種網(wǎng)絡(luò)協(xié)議。因此UDP編程的發(fā)送端只管發(fā)送就可以了,不用檢查網(wǎng)絡(luò)連接狀態(tài)。下面用例子來(lái)說(shuō)明怎樣編寫(xiě)UDP,并會(huì)詳細(xì)解釋每個(gè)API和數(shù)據(jù)類(lèi)型。

    7.1 UDP廣播發(fā)送程序

    下面是一個(gè)用UDP發(fā)送廣播報(bào)文的例子。

    #include <winsock2.h>

    #include <iostream.h>

    void main()

    {

        SOCKET sock;   //socket套接字

        char szMsg[] = "this is a UDP test package";//被發(fā)送的字段

        //1.啟動(dòng)SOCKET庫(kù),版本為2.0

        WORD wVersionRequested;

        WSADATA wsaData;

        int err;  

        wVersionRequested = MAKEWORD( 2, 0 ); 

        err = WSAStartup( wVersionRequested, &wsaData );

        if ( 0 != err ) //檢查Socket初始化是否成功

        {

           cout<<"Socket2.0初始化失敗,Exit!";

           return;

        }

        //檢查Socket庫(kù)的版本是否為2.0

        if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )

        {

           WSACleanup( );

           return;

        }

        //2.創(chuàng)建socket,

        sock = socket(

           AF_INET,           //internetwork: UDP, TCP, etc

           SOCK_DGRAM,        //SOCK_DGRAM說(shuō)明是UDP類(lèi)型

           0                  //protocol

           );

        if (INVALID_SOCKET == sock ) {

           cout<<"Socket 創(chuàng)建失敗,Exit!";

           return;

        }

        //3.設(shè)置該套接字為廣播類(lèi)型,

        bool opt = true;

        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char FAR *>(&opt), sizeof(opt));

        //4.設(shè)置發(fā)往的地址

        sockaddr_in addrto;            //發(fā)往的地址 

        memset(&addrto,0,sizeof(addrto));

        addrto.sin_family = AF_INET;               //地址類(lèi)型為internetwork

        addrto.sin_addr.s_addr = INADDR_BROADCAST; //設(shè)置ip為廣播地址

        addrto.sin_port = htons(7861);             //端口號(hào)為7861

        int nlen=sizeof(addrto);

        unsigned int uIndex = 1;

        while(true)

        {

           Sleep(1000); //程序休眠一秒

           //向廣播地址發(fā)送消息

           if( sendto(sock, szMsg, strlen(szMsg), 0, (sockaddr*)&addrto,nlen)

               == SOCKET_ERROR )

               cout<<WSAGetLastError()<<endl;

           else

               cout<<uIndex++<<":an UDP package is sended."<<endl;

        }

        if (!closesocket(sock)) //關(guān)閉套接字

        {

           WSAGetLastError();

           return;

        }

        if (!WSACleanup())       //關(guān)閉Socket庫(kù)

        {

           WSAGetLastError();

           return;

        }  

    }

    編譯命令:

    CL /c UDP_Send_Broadcast.cpp

    鏈接命令(注意如果找不到該庫(kù),則要在后面的/LIBPATH參數(shù)后加上庫(kù)的路徑):

    link UDP_Send_Broadcast.obj ws2_32.lib

    執(zhí)行命令:

    D:"Code"成品代碼"Socket"socket_src>UDP_Send_Broadcast.exe

    1:an UDP package is sended.

    2:an UDP package is sended.

    3:an UDP package is sended.

    4:an UDP package is sended.

    ^C

    下面一一解釋代碼中出現(xiàn)的數(shù)據(jù)類(lèi)型與API函數(shù)。有耐心的可以仔細(xì)看看,沒(méi)耐心的依葫蘆畫(huà)瓢也可以寫(xiě)程序了。

    7.2 SOCKET類(lèi)型

    SOCKETsocket套接字類(lèi)型,在WINSOCK2.H中有如下定義:

    typedef unsigned int    u_int;

    typedef u_int           SOCKET;

    可知套接字實(shí)際上就是一個(gè)無(wú)符號(hào)整型,它將被Socket環(huán)境管理和使用。套接字將被創(chuàng)建、設(shè)置、用來(lái)發(fā)送和接收數(shù)據(jù),最后會(huì)被關(guān)閉。

    7.3 WORD類(lèi)型、MAKEWORD、LOBYTEHIBYTE

    WORD類(lèi)型是一個(gè)16位的無(wú)符號(hào)整型,在WTYPES.H中被定義為:

    typedef unsigned short WORD;

    其目的是提供兩個(gè)字節(jié)的存儲(chǔ),在Socket中這兩個(gè)字節(jié)可以表示主版本號(hào)和副版本號(hào)。使用MAKEWORD宏可以給一個(gè)WORD類(lèi)型賦值。例如要表示主版本號(hào)2,副版本號(hào)0,可以使用以下代碼:

    WORD wVersionRequested;

    wVersionRequested = MAKEWORD( 2, 0 ); 

    注意低位內(nèi)存存儲(chǔ)主版本號(hào)2,高位內(nèi)存存儲(chǔ)副版本號(hào)0,其值為0x0002。使用宏LOBYTE可以讀取WORD的低位字節(jié),HIBYTE可以讀取高位字節(jié)。

    7.4 WSADATA類(lèi)型和LPWSADATA類(lèi)型

    WSADATA類(lèi)型是一個(gè)結(jié)構(gòu),描述了Socket庫(kù)的一些相關(guān)信息,其結(jié)構(gòu)定義如下:

    typedef struct WSAData {

            WORD                    wVersion;

            WORD                    wHighVersion;

            char                    szDescription[WSADESCRIPTION_LEN+1];

            char                    szSystemStatus[WSASYS_STATUS_LEN+1];

            unsigned short          iMaxSockets;

            unsigned short          iMaxUdpDg;

            char FAR *              lpVendorInfo;

    } WSADATA;

    typedef WSADATA FAR *LPWSADATA;

    值得注意的就是wVersion字段,存儲(chǔ)了Socket的版本類(lèi)型。LPWSADATAWSADATA的指針類(lèi)型。它們不用程序員手動(dòng)填寫(xiě),而是通過(guò)Socket的初始化函數(shù)WSAStartup讀取出來(lái)。

    7.5 WSAStartup函數(shù)

    WSAStartup函數(shù)被用來(lái)初始化Socket環(huán)境,它的定義如下:

    int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);

    其返回值為整型,調(diào)用方式為PASCAL(即標(biāo)準(zhǔn)類(lèi)型,PASCAL等于__stdcall),參數(shù)有兩個(gè),第一個(gè)參數(shù)為WORD類(lèi)型,指明了Socket的版本號(hào),第二個(gè)參數(shù)為WSADATA類(lèi)型的指針。

    若返回值為0,則初始化成功,若不為0則失敗。

    7.6 WSACleanup函數(shù)

    這是Socket環(huán)境的退出函數(shù)。返回值為0表示成功,SOCKET_ERROR表示失敗。

    7.7 socket函數(shù)

    socket的創(chuàng)建函數(shù),其定義為:

    SOCKET PASCAL FAR socket (int af, int type, int protocol);

    第一個(gè)參數(shù)為int af,代表網(wǎng)絡(luò)地址族,目前只有一種取值是有效的,即AF_INET,代表internet地址族;

    第二個(gè)參數(shù)為int type,代表網(wǎng)絡(luò)協(xié)議類(lèi)型,SOCK_DGRAM代表UDP協(xié)議,SOCK_STREAM代表TCP協(xié)議;

    第三個(gè)參數(shù)為int protocol,指定網(wǎng)絡(luò)地址族的特殊協(xié)議,目前無(wú)用,賦值0即可。

    返回值為SOCKET,若返回INVALID_SOCKET則失敗。

    7.8 setsockopt函數(shù)

    這個(gè)函數(shù)用來(lái)設(shè)置Socket的屬性,若不能正確設(shè)置socket屬性,則數(shù)據(jù)的發(fā)送和接收會(huì)失敗。定義如下:

    int PASCAL FAR setsockopt (SOCKET s, int level, int optname,

                               const char FAR * optval, int optlen);

    其返回值為int類(lèi)型,0代表成功,SOCKET_ERROR代表有錯(cuò)誤發(fā)生。

    第一個(gè)參數(shù)SOCKET s,代表要設(shè)置的套接字;

    第二個(gè)參數(shù)int level,代表要設(shè)置的屬性所處的層次,層次包含以下取值:SOL_SOCKET代表套接字層次;IPPROTO_TCP代表TCP協(xié)議層次,IPPROTO_IP代表IP協(xié)議層次(后面兩個(gè)我都沒(méi)有用過(guò));

    第三個(gè)參數(shù)int optname,代表設(shè)置參數(shù)的名稱(chēng),SO_BROADCAST代表允許發(fā)送廣播數(shù)據(jù)的屬性,其它屬性可參考MSDN

    第四個(gè)參數(shù)const char FAR * optval,代表指向存儲(chǔ)參數(shù)數(shù)值的指針,注意這里可能要使用reinterpret_cast類(lèi)型轉(zhuǎn)換;

    第五個(gè)參數(shù)int optlen,代表存儲(chǔ)參數(shù)數(shù)值變量的長(zhǎng)度。

    7.9 sockaddr_in、in_addr類(lèi)型,inet_addr、inet_ntoa函數(shù)

    sockaddr_in定義了socket發(fā)送和接收數(shù)據(jù)包的地址,定義:

    struct sockaddr_in {

            short   sin_family;

            u_short sin_port;

            struct in_addr sin_addr;

            char    sin_zero[8];

    };

    其中in_addr的定義如下:

    struct in_addr {

            union {

                    struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;

                    struct { u_short s_w1,s_w2; } S_un_w;

                    u_long S_addr;

            } S_un;

    首先闡述in_addr的含義,很顯然它是一個(gè)存儲(chǔ)ip地址的聯(lián)合體(忘記union含義的請(qǐng)看c++書(shū)),有三種表達(dá)方式:

    第一種用四個(gè)字節(jié)來(lái)表示IP地址的四個(gè)數(shù)字;

    第二種用兩個(gè)雙字節(jié)來(lái)表示IP地址;

    第三種用一個(gè)長(zhǎng)整型來(lái)表示IP地址。

    in_addr賦值的一種最簡(jiǎn)單方法是使用inet_addr函數(shù),它可以把一個(gè)代表IP地址的字符串賦值轉(zhuǎn)換為in_addr類(lèi)型,如

    addrto.sin_addr.s_addr=inet_addr("192.168.0.2");

    本例子中由于是廣播地址,所以沒(méi)有使用這個(gè)函數(shù)。其反函數(shù)是inet_ntoa,可以把一個(gè)in_addr類(lèi)型轉(zhuǎn)換為一個(gè)字符串。

    sockaddr_in的含義比in_addr的含義要廣泛,其各個(gè)字段的含義和取值如下:

    第一個(gè)字段short   sin_family,代表網(wǎng)絡(luò)地址族,如前所述,只能取值AF_INET

    第二個(gè)字段u_short sin_port,代表IP地址端口,由程序員指定;

    第三個(gè)字段struct in_addr sin_addr,代表IP地址;

    第四個(gè)字段char    sin_zero[8],很搞笑,是為了保證sockaddr_inSOCKADDR類(lèi)型的長(zhǎng)度相等而填充進(jìn)來(lái)的字段。

    以下代表指明了廣播地址,端口號(hào)為7861的一個(gè)地址:

        sockaddr_in addrto;            //發(fā)往的地址 

        memset(&addrto,0,sizeof(addrto));

        addrto.sin_family = AF_INET;               //地址類(lèi)型為internetwork

        addrto.sin_addr.s_addr = INADDR_BROADCAST; //設(shè)置ip為廣播地址

        addrto.sin_port = htons(7861);             //端口號(hào)為7861

    7.10           sockaddr類(lèi)型

    sockaddr類(lèi)型是用來(lái)表示Socket地址的類(lèi)型,同上面的sockaddr_in類(lèi)型相比,sockaddr的適用范圍更廣,因?yàn)?/span>sockaddr_in只適用于TCP/IP地址。Sockaddr的定義如下:

    struct sockaddr {

     u_short    sa_family;

     char       sa_data[14];

    };  

    可知sockaddr16個(gè)字節(jié),而sockaddr_in也有16個(gè)字節(jié),所以sockaddr_in是可以強(qiáng)制類(lèi)型轉(zhuǎn)換為sockaddr的。事實(shí)上也往往使用這種方法。

    7.11           Sleep函數(shù)

    線程掛起函數(shù),表示線程掛起一段時(shí)間。Sleep(1000)表示掛起一秒。定義于WINBASE.H頭文件中。WINBASE.H又被包含于WINDOWS.H中,然后WINDOWS.HWINSOCK2.H包含。所以在本例中使用Sleep函數(shù)不需要包含其它頭文件。

    7.12           sendto函數(shù)

    Socket中有兩套發(fā)送和接收函數(shù),一是sendtorecvfrom;二是sendrecv。前一套在函數(shù)參數(shù)中要指明地址;而后一套需要先將套接字和一個(gè)地址綁定,然后直接發(fā)送和接收,不需綁定地址。sendto的定義如下:

    int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags, const struct sockaddr FAR *to, int tolen);

    第一個(gè)參數(shù)就是套接字;

    第二個(gè)參數(shù)是要傳送的數(shù)據(jù)指針;

    第三個(gè)參數(shù)是要傳送的數(shù)據(jù)長(zhǎng)度(字節(jié)數(shù));

    第四個(gè)參數(shù)是傳送方式的標(biāo)識(shí),如果不需要特殊要求則可以設(shè)置為0,其它值請(qǐng)參考MSDN

    第五個(gè)參數(shù)是目標(biāo)地址,注意這里使用的是sockaddr的指針;

    第六個(gè)參數(shù)是地址的長(zhǎng)度;

    返回值為整型,如果成功,則返回發(fā)送的字節(jié)數(shù),失敗則返回SOCKET_ERROR

    7.13           WSAGetLastError函數(shù)

    該函數(shù)用來(lái)在Socket相關(guān)API失敗后讀取錯(cuò)誤碼,根據(jù)這些錯(cuò)誤碼可以對(duì)照查出錯(cuò)誤原因。

    7.14           closesocket

    關(guān)閉套接字,其參數(shù)為SOCKET類(lèi)型。成功返回0,失敗返回SOCKET_ERROR。

    7.15           小結(jié)

    總結(jié)以上內(nèi)容,寫(xiě)一個(gè)UDP發(fā)送程序的步驟如下:

    1.         WSAStartup函數(shù)初始化Socket環(huán)境;

    2.         socket函數(shù)創(chuàng)建一個(gè)套接字;

    3.         setsockopt函數(shù)設(shè)置套接字的屬性,例如設(shè)置為廣播類(lèi)型;很多時(shí)候該步驟可以省略;

    4.         創(chuàng)建一個(gè)sockaddr_in,并指定其IP地址和端口號(hào);

    5.         sendto函數(shù)向指定地址發(fā)送數(shù)據(jù),這里的目標(biāo)地址就是廣播地址;注意這里不需要綁定,即使綁定了,其地址也會(huì)被sendto中的參數(shù)覆蓋;若使用send函數(shù)則會(huì)出錯(cuò),因?yàn)?/span>send是面向連接的,而UDP是非連接的,只能使用sendto發(fā)送數(shù)據(jù);

    6.         closesocket函數(shù)關(guān)閉套接字;

    7.         WSACleanup函數(shù)關(guān)閉Socket環(huán)境。

    那么,與之類(lèi)似,一個(gè)UDP接收程序的步驟如下,注意接收方一定要bind套接字:

    1.         WSAStartup函數(shù)初始化Socket環(huán)境;

    2.         socket函數(shù)創(chuàng)建一個(gè)套接字;

    3.         setsockopt函數(shù)設(shè)置套接字的屬性,例如設(shè)置為廣播類(lèi)型;

    4.         創(chuàng)建一個(gè)sockaddr_in,并指定其IP地址和端口號(hào);

    5.         bind函數(shù)將套接字與接收的地址綁定起來(lái),然后調(diào)用recvfrom函數(shù)或者recv接收數(shù)據(jù); 注意這里一定要綁定,因?yàn)榻邮請(qǐng)?bào)文的套接字必須在網(wǎng)絡(luò)上有一個(gè)綁定的名稱(chēng)才能保證正確接收數(shù)據(jù);

    6.         closesocket函數(shù)關(guān)閉套接字;

    7.         WSACleanup函數(shù)關(guān)閉Socket環(huán)境。

    廣播接收程序見(jiàn)源程序代碼UDP_Recv_Broadcast.cpp。編譯、鏈接、執(zhí)行與UDP_Send_Broadcast類(lèi)似。

    7.16           UDP點(diǎn)對(duì)點(diǎn)發(fā)送接收程序

    廣播發(fā)送和接收使用并不廣泛,一般來(lái)說(shuō)指定發(fā)送和接收的IP比較常用。點(diǎn)對(duì)點(diǎn)方式的UDP發(fā)送和接收與上面的例子非常類(lèi)似,不同的就是需要指定一個(gè)具體的IP地址。并且不需要調(diào)用setsockopt設(shè)置socket的廣播屬性。

    其具體源代碼見(jiàn)UDP_Send_P2P.cppUDP_Recv_P2P.cpp。

    注意在使用這兩個(gè)程序時(shí)要設(shè)為自己所需的IP。

    8         TCP

    TCPUDP最大的不同之處在于TCP是一個(gè)面向連接的協(xié)議,在進(jìn)行數(shù)據(jù)收發(fā)之前TCP必須進(jìn)行連接,并且在收發(fā)的時(shí)候必須保持該連接。

    發(fā)送方的步驟如下(省略了Socket環(huán)境的初始化、關(guān)閉等內(nèi)容):

    1.         socket函數(shù)創(chuàng)建一個(gè)套接字sock;

    2.         bindsock綁定到本地地址;

    3.         listen偵聽(tīng)sock套接字;

    4.         accept函數(shù)接收客戶方的連接,返回客戶方套接字clientSocket

    5.         在客戶方套接字clientSocket上使用send發(fā)送數(shù)據(jù);

    6.         closesocket函數(shù)關(guān)閉套接字sockclientSocket

    而接收方的步驟如下:

    1.         socket函數(shù)創(chuàng)建一個(gè)套接字sock

    2.         創(chuàng)建一個(gè)指向服務(wù)方的遠(yuǎn)程地址;

    3.         connectsock連接到服務(wù)方,使用遠(yuǎn)程地址;

    4.         在套接字上使用recv接收數(shù)據(jù);

    5.         closesocket函數(shù)關(guān)閉套接字sock;

    值得注意的是,在服務(wù)方有兩個(gè)地址,一個(gè)是本地地址myaddr,另一個(gè)是目標(biāo)地址addrto。本地地址myaddr用來(lái)和本地套接字sock綁定,目標(biāo)地址被sock用來(lái)accept客戶方套接字clientSocket。這樣sockclientSocket連接成功,這兩個(gè)地址也連接上了。在服務(wù)方使用clientSocket發(fā)送數(shù)據(jù),則會(huì)從本地地址傳送到目標(biāo)地址。

    在客戶方只有一個(gè)地址,即來(lái)源地址addrfrom。這個(gè)地址被用來(lái)connect遠(yuǎn)程的服務(wù)方套接字,connect成功則本地套接字與遠(yuǎn)程的來(lái)源地址連接了,因此可以使用該套接字接收遠(yuǎn)程數(shù)據(jù)。其實(shí)這時(shí)客戶方套接字已經(jīng)被隱性的綁定了本地地址,所以不需要顯式調(diào)用bind函數(shù),即使調(diào)用也不會(huì)影像結(jié)果。

    具體源代碼見(jiàn)TCP_Send.cppTCP_Recv.cpp。注意將源代碼中的IP地址修改為符合自己需要的IP。為了減少代碼復(fù)雜性,沒(méi)有使用讀取本機(jī)IP的代碼,后續(xù)例子程序中含有此功能代碼。

    8.1 bind函數(shù)

    bind函數(shù)用來(lái)將一個(gè)套接字綁定到一個(gè)IP地址。一般只在服務(wù)方(即數(shù)據(jù)發(fā)送方)調(diào)用,很多函數(shù)會(huì)隱式的調(diào)用bind函數(shù)。

    8.2 listen函數(shù)

    從服務(wù)方監(jiān)聽(tīng)客戶方的連接。同一個(gè)套接字可以多次監(jiān)聽(tīng)。

    8.3 connectaccept函數(shù)

    connect是客戶方連接服務(wù)方的函數(shù),而accept是服務(wù)方同意客戶方連接的函數(shù)。這兩個(gè)配套函數(shù)分別在各自的程序中被成功調(diào)用后就可以收發(fā)數(shù)據(jù)了。

    8.4 sendrecv函數(shù)

    sendrecv是用來(lái)發(fā)送和接收數(shù)據(jù)的兩個(gè)重要函數(shù)。send只能在已經(jīng)連接的狀態(tài)下使用,而recv可以面向連接和非連接的狀態(tài)下使用。

    send的定義如下:

    int WSAAPI send(

        SOCKET s,

        const char FAR * buf,

        int len,

        int flags

        );

    其參數(shù)的含義和sendto中的前四個(gè)參數(shù)一樣。而recv的定義如下:

    int WSAAPI recv(

        SOCKET s,

        char FAR * buf,

        int len,

        int flags

        );

    其參數(shù)含義與send中的參數(shù)含義一樣。

    9         一個(gè)局域網(wǎng)聊天工具的編寫(xiě)

    掌握了以上關(guān)于socket的基本用法,編寫(xiě)一個(gè)局域網(wǎng)聊天程序也就變得非常簡(jiǎn)單,如同設(shè)計(jì)一個(gè)普通的對(duì)話框程序一樣。

    9.1 功能設(shè)計(jì)

    功能設(shè)計(jì)如下:

    1.         要能夠指定聊天對(duì)象的IP和端口(端口可以內(nèi)部確定);

    2.         要能夠發(fā)送消息給指定聊天對(duì)象;

    3.         要能夠接收聊天對(duì)象的消息;

    4.         接收消息時(shí)要播放聲音;

    5.         接收消息時(shí)如果當(dāng)前對(duì)話框不是最前端,要閃動(dòng)圖標(biāo);

    6.         要有托盤(pán)圖標(biāo),可以將對(duì)話框收入托盤(pán);

    9.2 功能實(shí)現(xiàn)

    將內(nèi)部端口設(shè)為3456,提供一個(gè)IP地址控件來(lái)設(shè)置聊天對(duì)象的IP。該控件必須能夠讀取IP地址并賦值給內(nèi)部變量。將地址轉(zhuǎn)換為in_addr類(lèi)型。

    發(fā)送消息需要使用一個(gè)套接字。

    接收消息也需要使用一個(gè)套接字,由于發(fā)送消息也使用了一個(gè)套接字,為了在同一個(gè)進(jìn)程中同時(shí)發(fā)送和接收消息,需要使用多線程技術(shù),將發(fā)送消息的線程設(shè)為主線程;而接收消息的線程設(shè)為子線程,子線程只負(fù)責(zé)接收UDP消息,在收到消息后顯示到主界面中。

    接收消息時(shí)播放聲音這個(gè)功能在子線程中完成,使用sndPlaySound函數(shù),并提供一個(gè)wav文件即可。

    閃動(dòng)圖標(biāo)這個(gè)最白癡的功能需要使用一個(gè)Timer,在主對(duì)話框類(lèi)中添加一個(gè)OnTimer函數(shù),定時(shí)檢查當(dāng)前窗口狀態(tài)變量是否為假,若為假就每次設(shè)置另一個(gè)圖標(biāo)。若當(dāng)前窗口顯示到最頂端,則設(shè)置為默認(rèn)圖標(biāo)。

    托盤(pán)圖標(biāo)功能用網(wǎng)上下載的CtrayIcon類(lèi)輕松搞定。需要提供一個(gè)自定義消息,一個(gè)彈出菜單資源。

    9.3 所需資源

    頭文件:winsock2.h,Mmsystem.h

    庫(kù)文件:ws2_32.lib,winmm.lib

    dllWs2_32.dll,winmm.dll

    wav文件:recv.wav

    圖標(biāo):一個(gè)主程序圖標(biāo)IDI_MAIN、四個(gè)變化圖標(biāo)IDI_ICON1~4;

    菜單:一個(gè)給托盤(pán)用的彈出菜單IDR_TRAYICON;

    說(shuō)明,Mmsystem.hwinmm.lib、winmm.dll是為了那個(gè)播放聲音的功能。

    9.4 托盤(pán)功能

    托盤(pán)屬于界面功能,是變更很少的需求,因此首先完成。

    1.         引入TRAYICON.HTRAYICON.cpp兩個(gè)類(lèi);

    2.         CLANTalkDlg類(lèi)中加入一個(gè)CTrayIconm_trayIcon;屬性;

    3.         CLANTalkDlg的構(gòu)造函數(shù)中初始化m_trayIcon,m_trayIcon(IDR_TRAYICON);

    4.         添加一個(gè)自定義消息WM_MY_TRAY_NOTIFICATION,即在三個(gè)地方添加消息定義、消息響應(yīng)函數(shù)、消息映射;

    5.         InitDialog方法中調(diào)用托盤(pán)初始化的兩個(gè)函數(shù)      m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION);    m_trayIcon.SetIcon(IDI_MAIN);

    6.         重寫(xiě)OnClose方法,添加彈出菜單的OnAppSuspendOnAppOpen以及OnAppAbout方法;

    7.         重寫(xiě)對(duì)話框的OnCancel方法。

    9.5 動(dòng)態(tài)圖標(biāo)

    動(dòng)態(tài)圖標(biāo)也是界面相關(guān)功能,首先完成。

    1.         添加四個(gè)HICON變量m_hIcon1,m_hIcon2,m_hIcon3,m_hIcon4

    2.         在構(gòu)造函數(shù)中初始化這四個(gè)變量m_hIcon1 = AfxGetApp()->LoadIcon(IDI_ICON1);

    3.         InitDialog中設(shè)置調(diào)用SetTimer(1,300,NULL);設(shè)置一個(gè)timerid1,間隔為300微秒;

    4.         添加一個(gè)布爾屬性m_bDynamicIcon,指示目前是否需要?jiǎng)討B(tài)圖標(biāo),并給出一個(gè)設(shè)置函數(shù)SetDynamicIcon;

    5.         添加一個(gè)OnTimer函數(shù),讓每次timer調(diào)用時(shí)根據(jù)m_bDynamicIcon的值修改圖標(biāo);

    兩個(gè)地方是用來(lái)設(shè)置動(dòng)態(tài)圖標(biāo)的,一個(gè)是當(dāng)程序收到消息并且程序不在桌面頂端時(shí),這時(shí)設(shè)置為動(dòng)態(tài)圖標(biāo),在后面的消息接收線程中處理;二是當(dāng)程序顯示到桌面頂端時(shí),設(shè)置為非動(dòng)態(tài);

    重載OnActivate方法可以完成第二個(gè)時(shí)刻的要求。當(dāng)窗口狀態(tài)為WA_ACTIVE或者WA_CLICKACTIVE時(shí)SetDynamicIcon(false),否則設(shè)置SetDynamicIcon(true);

    9.6 發(fā)送UDP報(bào)文功能

    發(fā)送UDP報(bào)文只需在主線程中完成,需要以下步驟:

    1.         初始化Socket環(huán)境,這可以在CLANTalkAppInitInstance中完成,同理關(guān)閉Socket環(huán)境在ExitInstance中完成;我們可以使用前面的方法,也可以直接調(diào)用MFC中的AfxSocketInit函數(shù),這個(gè)函數(shù)可以確保在程序結(jié)束時(shí)自動(dòng)關(guān)閉Socket環(huán)境;

    2.         創(chuàng)建socket,考慮到報(bào)錯(cuò)信息需要彈出對(duì)話框,因此不在CLANTalkDlg的構(gòu)造函數(shù)中創(chuàng)建,而是在InitDialog中構(gòu)建;發(fā)送報(bào)文的socketm_sendSock;

    3.         設(shè)置目的地址功能,需要一個(gè)地址賦值函數(shù)setAddress(char* szAddr);可以將一個(gè)字符串地址賦值給sockaddr_in形式的地址;在CLANTalkDlg中增加一個(gè)sockaddr_in m_addrto;屬性;

    4.         讀取文本框中的文字,用sendto發(fā)送到對(duì)象地址;

    5.         清空文本框,在記錄框中添加聊天記錄。

    這時(shí)可以使用前面的UDP簡(jiǎn)單接收程序來(lái)輔助測(cè)試,因?yàn)榇藭r(shí)還未完成報(bào)文接收功能。

    9.7 接收UDP報(bào)文功能

    接收UDP報(bào)文要考慮幾個(gè)問(wèn)題,第一個(gè)是要?jiǎng)?chuàng)建一個(gè)子線程,在子線程中接收?qǐng)?bào)文;第二是接收?qǐng)?bào)文和發(fā)送報(bào)文要有互斥機(jī)制,以免沖突;第三是接收到報(bào)文要播放聲音;第四是接收?qǐng)?bào)文且當(dāng)前窗口不在桌面頂端要調(diào)用動(dòng)態(tài)圖標(biāo)功能。

    按照以上需求設(shè)計(jì)步驟如下:

    1.         創(chuàng)建接收套接字m_recvSock,

    2.         利用gethostnamegethostbyname等函數(shù)獲取本機(jī)IP,并將套接字bind到該地址;

    3.         添加一個(gè)CwinThread* m_pRecvThread屬性,并在InitDialog中調(diào)用AfxBeginThread創(chuàng)建子線程;

    4.         編寫(xiě)子線程運(yùn)行函數(shù)void RecvProcess(LPVOID pParam),這時(shí)一個(gè)全局函數(shù),為了方便調(diào)用CLANTalkDlg類(lèi)中的各種變量與方法,將CLANTalkDlg類(lèi)的指針作為參數(shù)傳入子線程函數(shù),并將RecvProcess設(shè)置為CLANTalkDlg類(lèi)的友元。

    5.         子線程函數(shù)中完成以下功能:利用recv接收?qǐng)?bào)文;保存聊天記錄;判斷當(dāng)前窗口是否在前臺(tái),并修改動(dòng)態(tài)圖標(biāo)屬性;播放聲音。

    6.         用來(lái)記錄聊天信息的ClistBoxSort屬性要去掉,否則記錄會(huì)按內(nèi)容排序,很不好看。在RC編輯器中去掉這個(gè)屬性即可。

    7.         最后要注意,在主線程退出時(shí)要保證子線程退出,但此時(shí)子線程還阻塞在recv方法上,因此主線程向自己發(fā)送一條消息消除阻塞,同時(shí)改變子線程退出標(biāo)志保證子線程可以退出。

    9.8 設(shè)置聊天對(duì)象IP

    點(diǎn)擊“確認(rèn)對(duì)象”按鈕時(shí),檢測(cè)IP地址控件,如果IP地址有效,則將IP地址讀入內(nèi)部屬性。這個(gè)IP地址作為發(fā)送信息的目標(biāo)地址。

    這個(gè)設(shè)置只能設(shè)置發(fā)送消息的對(duì)象,所有人都可以向本機(jī)發(fā)送信息,只要他的端口是正確的。

    9.9 編譯鏈接和運(yùn)行

    下載壓縮包后可以打開(kāi)VC工程編譯鏈接,若直接運(yùn)行則可以點(diǎn)擊LANTalkExeFile目錄中的可執(zhí)行文件,這個(gè)目標(biāo)包含了運(yùn)行所需要的所有dll和資源文件。

    當(dāng)然,如果需要可以用InstallShield做一個(gè)安裝程序,不過(guò)看來(lái)是沒(méi)有必要的。

    9.10           小結(jié)

    這個(gè)聊天程序很簡(jiǎn)單,但是基本上具有了一個(gè)框架,可以有最簡(jiǎn)單的聊天功能。要在此基礎(chǔ)上進(jìn)行擴(kuò)展幾乎已經(jīng)沒(méi)有什么技術(shù)問(wèn)題了。

    10    使用好的Socket包可以簡(jiǎn)化開(kāi)發(fā)過(guò)程

    本文中所有的技術(shù)盡量采用最原始的方式來(lái)使用。例如多線程使用的是AfxBeginThread,套接字使用了最原始的套接字,并在很多地方直接使用了SDK函數(shù),而盡量避免了MFC等代碼框架,這是為了方便他人掌握技術(shù)的最基本內(nèi)涵。

    其實(shí)在具體的編程中,當(dāng)然是怎么方便怎么來(lái),Socket和多線程以及界面等功能都有大量方便可用的代碼庫(kù),復(fù)用這些代碼庫(kù)會(huì)比自己動(dòng)手寫(xiě)方便很多。但是,掌握了基本原理再使用這些庫(kù),事半功倍!

    竟然寫(xiě)了14頁(yè),真是pf自己?。?/span>


    評(píng)論

    # re: Socket編程指南及示例程序[未登錄](méi)  回復(fù)  更多評(píng)論   

    2007-11-04 08:23 by Base
    來(lái),先贊一個(gè)

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2007-11-08 00:33 by 林克
    受益了!謝謝!!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2007-11-18 21:16 by nate
    非常感謝?。。?!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2007-11-21 17:04 by mq
    很好,能用,謝謝你,

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2007-11-25 15:47 by 瘋的邊緣
    你多大了?

    # re: Socket編程指南及示例程序[未登錄](méi)  回復(fù)  更多評(píng)論   

    2007-11-30 09:26 by 深藍(lán)
    太棒了

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2007-11-30 14:58 by 電話
    收益頗多

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2008-09-02 15:48 by huhusu
    很詳盡啊 謝謝了

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2008-10-16 11:24 by 英雄的故事
    不深,適合初學(xué)者

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2008-10-16 11:25 by 英雄的故事
    寫(xiě)得再深點(diǎn)廣點(diǎn)可能會(huì)好點(diǎn)

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2009-06-19 00:57 by qeewei
    看到這篇文章被廣泛轉(zhuǎn)載,這里是原創(chuàng)吧。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2009-06-19 21:55 by wxb_nudt
    @qeewei
    是的,不過(guò)我很懶,很久沒(méi)有寫(xiě)什么了。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2009-07-21 10:46 by ycs
    很好很好,受益頗多!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2009-09-28 13:53 by hotice
    支持LZ,好文。。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2010-05-25 23:20 by 藍(lán)天翔
    例子程序可惜用的還是MFC。難道不用MFC就不能簡(jiǎn)單的實(shí)現(xiàn)嗎?

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2010-10-24 10:47 by caicai
    寫(xiě)的已經(jīng)很不錯(cuò)了。相當(dāng)?shù)囊锥兄x

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2010-11-17 09:11 by ykq
    解釋的很詳細(xì)

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2010-11-28 11:03 by newway
    很好的東西,謝謝樓主!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2010-11-29 07:53 by sodakki
    這正是我需要的。十分感謝。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2011-04-21 15:54 by bian
    很詳細(xì),比在網(wǎng)上找的其他的好多了

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2012-06-07 21:27 by 阿和
    作者太棒了,佩服!
    這個(gè)寫(xiě)的很詳實(shí),很認(rèn)真,我終于稍微看懂點(diǎn)了

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2012-10-11 18:22 by 方法
    不錯(cuò)

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2012-10-17 22:15 by 淡淡的
    非常感謝!1!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2012-12-15 18:58 by sky-freeprisoner
    在學(xué)習(xí)SOCKET,看到 3再說(shuō)兩句,果斷關(guān)閉其他頁(yè)面。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2012-12-19 15:31 by terrox
    寫(xiě)的真好,學(xué)到很多東西了。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-02-19 16:18 by ckevin
    寫(xiě)的很好 收益良多 在Linux下編程也很有借鑒價(jià)值!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-03-16 09:52 by 一枚菜鳥(niǎo)
    寫(xiě)的真好!學(xué)到很多!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-03-17 11:49 by 歡子
    我想用C語(yǔ)言寫(xiě)一個(gè)程序,主要是實(shí)現(xiàn)將兩臺(tái)機(jī)子連接起來(lái)的功能,但我不是很了解應(yīng)該怎樣去著手,求解

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-04-15 18:56 by 芝華士碎冰
    LZ寫(xiě)的很好,提一點(diǎn)小小的意見(jiàn):
    創(chuàng)建socket時(shí)
    sock = socket(

    AF_INET, //internetwork: UDP, TCP, etc

    SOCK_DGRAM, //SOCK_DGRAM說(shuō)明是UDP類(lèi)型

    0 //protocol

    );
    第一個(gè)注釋里TCP的的第一個(gè)參數(shù)應(yīng)該是PF_INFT與UDP不同,第二個(gè)參數(shù)值SOCK_DGRAM其實(shí)是說(shuō)明他是數(shù)據(jù)報(bào)類(lèi)型。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-05-21 16:16 by 一枚菜鳥(niǎo)
    寫(xiě)的真是太好了,保存下來(lái) ,好好仔細(xì)看看

    # re: Socket編程指南及示例程序[未登錄](méi)  回復(fù)  更多評(píng)論   

    2013-06-01 08:20 by 1
    樓主好人啊

    # re: Socket編程指南及示例程序[未登錄](méi)  回復(fù)  更多評(píng)論   

    2013-08-01 12:35 by ws
    好東西啊,不容錯(cuò)過(guò)。

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-08-06 07:45 by kaly
    寫(xiě)得真好

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-09-27 16:14 by anp
    a

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-09-27 16:14 by anp
    @anp
    hi

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-10-06 18:18 by 小敗
    能不能教教我 我很感興趣

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-10-09 11:51 by suiyue
    大神,求教1

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-10-14 07:39 by 不是不懂
    謝謝樓主分享。受教了,

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-11-05 12:15 by xc
    @Base
    受教了

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2013-12-31 17:49 by
    很贊 謝謝!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2014-01-03 15:32 by hold住
    源碼下載不了,頁(yè)面打不開(kāi),還有誰(shuí)有源碼嗎,求助!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2014-08-10 16:35 by gildor
    總覺(jué)得服務(wù)端和客戶端弄反了

    # re: Socket編程指南及示例程序[未登錄](méi)  回復(fù)  更多評(píng)論   

    2014-10-29 16:26 by a
    相對(duì)清晰一些了,謝謝!

    # re: Socket編程指南及示例程序  回復(fù)  更多評(píng)論   

    2016-04-09 20:49 by lhf
    太棒了。相對(duì)清晰一些了
    主站蜘蛛池模板: 亚洲福利电影一区二区?| 久久久久久a亚洲欧洲AV| 香蕉大伊亚洲人在线观看| 99爱在线精品视频免费观看9| 亚洲中文字幕久久精品无码喷水| 国产精品亚洲一区二区无码| 大陆一级毛片免费视频观看| 亚洲乱人伦中文字幕无码| 四虎www免费人成| 亚洲AV永久无码精品网站在线观看 | 91情侣在线精品国产免费| 亚洲最大在线观看| 日韩精品无码区免费专区| 亚洲人成色77777在线观看| 日韩黄色免费观看| 午夜不卡AV免费| 亚洲精品美女久久久久99| 久草免费福利视频| 亚洲黄网站wwwwww| 妞干网免费观看视频| 国产亚洲精品2021自在线| 亚洲日本中文字幕一区二区三区 | 天堂在线免费观看| 亚洲视频中文字幕| 无人影院手机版在线观看免费| 中文字幕亚洲情99在线| 亚洲av无码天堂一区二区三区| 国产区在线免费观看| 337p欧洲亚洲大胆艺术| 免费无码又爽又刺激毛片| 一区二区免费电影| 亚洲av激情无码专区在线播放| 成人黄色免费网站| 色多多A级毛片免费看| 久久久影院亚洲精品| 最近中文字幕免费mv视频7| 一级做α爱过程免费视频| 亚洲黄色高清视频| 国产又大又长又粗又硬的免费视频| 精品无码国产污污污免费网站国产| 久久精品国产亚洲精品2020|