1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        C/C++ 套接字通信類的封裝

        共 6280字,需瀏覽 13分鐘

         ·

        2021-12-13 12:53

        在掌握了基于 TCP 的套接字通信流程之后,為了方便使用,提高編碼效率,可以對(duì)通信操作進(jìn)行封裝,本著有淺入深的原則,先基于 C 語(yǔ)言進(jìn)行面向過(guò)程的函數(shù)封裝,然后再基于 C++ 進(jìn)行面向?qū)ο蟮念惙庋b。

        1. 基于 C 語(yǔ)言的封裝

        基于 TCP 的套接字通信分為兩部分:服務(wù)器端通信和客戶端通信。我們只要掌握了通信流程,封裝出對(duì)應(yīng)的功能函數(shù)也就不在話下了,先來(lái)回顧一下通信流程:

        服務(wù)器端

        • 創(chuàng)建用于監(jiān)聽(tīng)的套接字
        • 將用于監(jiān)聽(tīng)的套接字和本地的 IP 以及端口進(jìn)行綁定
        • 啟動(dòng)監(jiān)聽(tīng)
        • 等待并接受新的客戶端連接,連接建立得到用于通信的套接字和客戶端的 IP、端口信息
        • 使用得到的通信的套接字和客戶端通信(接收和發(fā)送數(shù)據(jù))
        • 通信結(jié)束,關(guān)閉套接字(監(jiān)聽(tīng) + 通信)

        客戶端

        • 創(chuàng)建用于通信的套接字
        • 使用服務(wù)器端綁定的 IP 和端口連接服務(wù)器
        • 使用通信的套接字和服務(wù)器通信(發(fā)送和接收數(shù)據(jù))
        • 通信結(jié)束,關(guān)閉套接字(通信)

        1.1 函數(shù)聲明

        通過(guò)通信流程可以看出服務(wù)器和客戶端有些操作步驟是相同的,因此封裝的功能函數(shù)是可以共用的,相關(guān)的通信函數(shù)聲明如下:

        ///////////////////////////////////////////////////?
        ////////////////////?服務(wù)器?///////////////////////
        ///////////////////////////////////////////////////
        int?bindSocket(int?lfd,?unsigned?short?port);
        int?setListen(int?lfd);
        int?acceptConn(int?lfd,?struct?sockaddr_in?*addr);

        ///////////////////////////////////////////////////?
        ////////////////////?客戶端?///////////////////////
        ///////////////////////////////////////////////////
        int?connectToHost(int?fd,?const?char*?ip,?unsigned?short?port);

        ///////////////////////////////////////////////////?
        /////////////////////?共用?////////////////////////
        ///////////////////////////////////////////////////
        int?createSocket();
        int?sendMsg(int?fd,?const?char*?msg);
        int?recvMsg(int?fd,?char*?msg,?int?size);
        int?closeSocket(int?fd);
        int?readn(int?fd,?char*?buf,?int?size);
        int?writen(int?fd,?const?char*?msg,?int?size);

        關(guān)于函數(shù) readn()writen() 的作用請(qǐng)參考TCP數(shù)據(jù)粘包的處理

        1.2 函數(shù)定義

        //?創(chuàng)建監(jiān)套接字
        int?createSocket()
        {
        ????int?fd?=?socket(AF_INET,?SOCK_STREAM,?0);
        ????if(fd?==?-1)
        ????{
        ????????perror("socket");
        ????????return?-1;
        ????}
        ????printf("套接字創(chuàng)建成功,?fd=%d\n",?fd);
        ????return?fd;
        }

        //?綁定本地的IP和端口
        int?bindSocket(int?lfd,?unsigned?short?port)
        {
        ????struct?sockaddr_in?saddr;
        ????saddr.sin_family?=?AF_INET;
        ????saddr.sin_port?=?htons(port);
        ????saddr.sin_addr.s_addr?=?INADDR_ANY;??//?0?=?0.0.0.0
        ????int?ret?=?bind(lfd,?(struct?sockaddr*)&saddr,?sizeof(saddr));
        ????if(ret?==?-1)
        ????{
        ????????perror("bind");
        ????????return?-1;
        ????}
        ????printf("套接字綁定成功,?ip:?%s,?port:?%d\n",
        ???????????inet_ntoa(saddr.sin_addr),?port);
        ????return?ret;
        }

        //?設(shè)置監(jiān)聽(tīng)
        int?setListen(int?lfd)
        {
        ????int?ret?=?listen(lfd,?128);
        ????if(ret?==?-1)
        ????{
        ????????perror("listen");
        ????????return?-1;
        ????}
        ????printf("設(shè)置監(jiān)聽(tīng)成功...\n");
        ????return?ret;
        }

        //?阻塞并等待客戶端的連接
        int?acceptConn(int?lfd,?struct?sockaddr_in?*addr)
        {
        ????int?cfd?=?-1;
        ????if(addr?==?NULL)
        ????{
        ????????cfd?=?accept(lfd,?NULL,?NULL);
        ????}
        ????else
        ????{
        ????????int?addrlen?=?sizeof(struct?sockaddr_in);
        ????????cfd?=?accept(lfd,?(struct?sockaddr*)addr,?&addrlen);
        ????}
        ????if(cfd?==?-1)
        ????{
        ????????perror("accept");
        ????????return?-1;
        ????}???????
        ????printf("成功和客戶端建立連接...\n");
        ????return?cfd;?
        }

        //?接收數(shù)據(jù)
        int?recvMsg(int?cfd,?char**?msg)
        {
        ????if(msg?==?NULL?||?cfd?<=?0)
        ????{
        ????????return?-1;
        ????}
        ????//?接收數(shù)據(jù)
        ????//?1.?讀數(shù)據(jù)頭
        ????int?len?=?0;
        ????readn(cfd,?(char*)&len,?4);
        ????len?=?ntohl(len);
        ????printf("數(shù)據(jù)塊大小:?%d\n",?len);

        ????//?根據(jù)讀出的長(zhǎng)度分配內(nèi)存
        ????char?*buf?=?(char*)malloc(len+1);
        ????int?ret?=?readn(cfd,?buf,?len);
        ????if(ret?!=?len)
        ????{
        ????????return?-1;
        ????}
        ????buf[len]?=?'\0';
        ????*msg?=?buf;

        ????return?ret;
        }

        //?發(fā)送數(shù)據(jù)
        int?sendMsg(int?cfd,?char*?msg,?int?len)
        {
        ???if(msg?==?NULL?||?len?<=?0)
        ???{
        ???????return?-1;
        ???}
        ???//?申請(qǐng)內(nèi)存空間:?數(shù)據(jù)長(zhǎng)度?+?包頭4字節(jié)(存儲(chǔ)數(shù)據(jù)長(zhǎng)度)
        ???char*?data?=?(char*)malloc(len+4);
        ???int?bigLen?=?htonl(len);
        ???memcpy(data,?&bigLen,?4);
        ???memcpy(data+4,?msg,?len);
        ???//?發(fā)送數(shù)據(jù)
        ???int?ret?=?writen(cfd,?data,?len+4);
        ???return?ret;
        }

        //?連接服務(wù)器
        int?connectToHost(int?fd,?const?char*?ip,?unsigned?short?port)
        {
        ????//?2.?連接服務(wù)器IP?port
        ????struct?sockaddr_in?saddr;
        ????saddr.sin_family?=?AF_INET;
        ????saddr.sin_port?=?htons(port);
        ????inet_pton(AF_INET,?ip,?&saddr.sin_addr.s_addr);
        ????int?ret?=?connect(fd,?(struct?sockaddr*)&saddr,?sizeof(saddr));
        ????if(ret?==?-1)
        ????{
        ????????perror("connect");
        ????????return?-1;
        ????}
        ????printf("成功和服務(wù)器建立連接...\n");
        ????return?ret;
        }

        //?關(guān)閉套接字
        int?closeSocket(int?fd)
        {
        ????int?ret?=?close(fd);
        ????if(ret?==?-1)
        ????{
        ????????perror("close");
        ????}
        ????return?ret;
        }

        //?接收指定的字節(jié)數(shù)
        //?函數(shù)調(diào)用成功返回?size
        int?readn(int?fd,?char*?buf,?int?size)
        {
        ????int?nread?=?0;
        ????int?left?=?size;
        ????char*?p?=?buf;

        ????while(left?>?0)
        ????{
        ????????if((nread?=?read(fd,?p,?left))?>?0)
        ????????{
        ????????????p?+=?nread;
        ????????????left?-=?nread;
        ????????}
        ????????else?if(nread?==?-1)
        ????????{
        ????????????return?-1;
        ????????}
        ????}
        ????return?size;
        }

        //?發(fā)送指定的字節(jié)數(shù)
        //?函數(shù)調(diào)用成功返回?size
        int?writen(int?fd,?const?char*?msg,?int?size)
        {
        ????int?left?=?size;
        ????int?nwrite?=?0;
        ????const?char*?p?=?msg;

        ????while(left?>?0)
        ????{
        ????????if((nwrite?=?write(fd,?msg,?left))?>?0)
        ????????{
        ????????????p?+=?nwrite;
        ????????????left?-=?nwrite;
        ????????}
        ????????else?if(nwrite?==?-1)
        ????????{
        ????????????return?-1;
        ????????}
        ????}
        ????return?size;
        }

        2. 基于 C++ 的封裝

        編寫 C++ 程序應(yīng)當(dāng)遵循面向?qū)ο笕兀悍庋b、繼承、多態(tài)。簡(jiǎn)單地說(shuō)就是封裝之后的類可以隱藏掉某些屬性使操作更簡(jiǎn)單并且類的功能要單一,如果要代碼重用可以進(jìn)行類之間的繼承,如果要讓函數(shù)的使用更加靈活可以使用多態(tài)。因此,我們需要封裝兩個(gè)類:客戶端類和服務(wù)器端的類。

        2.1 版本 1

        根據(jù)面向?qū)ο蟮乃枷?,整個(gè)通信過(guò)程不管是監(jiān)聽(tīng)還是通信的套接字都是可以封裝到類的內(nèi)部并且將其隱藏掉,這樣相關(guān)操作函數(shù)的參數(shù)也就隨之減少了,使用者用起來(lái)也更簡(jiǎn)便。

        2.1.1 客戶端

        class?TcpClient
        {
        public:
        ????TcpClient();
        ????~TcpClient();
        ????//?int?connectToHost(int?fd,?const?char*?ip,?unsigned?short?port);
        ????int?connectToHost(string?ip,?unsigned?short?port);

        ????//?int?sendMsg(int?fd,?const?char*?msg);
        ????int?sendMsg(string?msg);
        ????//?int?recvMsg(int?fd,?char*?msg,?int?size);
        ????string?recvMsg();
        ????
        ????//?int?createSocket();
        ????//?int?closeSocket(int?fd);

        private:
        ????//?int?readn(int?fd,?char*?buf,?int?size);
        ????int?readn(char*?buf,?int?size);
        ????//?int?writen(int?fd,?const?char*?msg,?int?size);
        ????int?writen(const?char*?msg,?int?size);
        ????
        private:
        ????int?cfd;?//?通信的套接字
        };

        通過(guò)對(duì)客戶端的操作進(jìn)行封裝,我們可以看到有如下的變化:

        • 文件描述被隱藏了,封裝到了類的內(nèi)部已經(jīng)無(wú)法進(jìn)行外部訪問(wèn)
        • 功能函數(shù)的參數(shù)變少了,因?yàn)轭惓蓡T函數(shù)可以直接使用類內(nèi)部的成員變量。
        • 創(chuàng)建和銷毀套接字的函數(shù)去掉了,這兩個(gè)操作可以分別放到構(gòu)造和析構(gòu)函數(shù)內(nèi)部進(jìn)行處理。
        • 在 C++ 中可以適當(dāng)?shù)膶?char* 替換為 string 類,這樣操作字符串就更簡(jiǎn)便一些。

        2.1.2 服務(wù)器端

        class?TcpServer
        {
        public:
        ????TcpServer();
        ????~TcpServer();

        ????//?int?bindSocket(int?lfd,?unsigned?short?port)?+?int?setListen(int?lfd)
        ????int?setListen(unsigned?short?port);
        ????//?int?acceptConn(int?lfd,?struct?sockaddr_in?*addr);
        ????int?acceptConn(struct?sockaddr_in?*addr);

        ????//?int?sendMsg(int?fd,?const?char*?msg);
        ????int?sendMsg(string?msg);
        ????//?int?recvMsg(int?fd,?char*?msg,?int?size);
        ????string?recvMsg();
        ????
        ????//?int?createSocket();
        ????//?int?closeSocket(int?fd);

        private:
        ????//?int?readn(int?fd,?char*?buf,?int?size);
        ????int?readn(char*?buf,?int?size);
        ????//?int?writen(int?fd,?const?char*?msg,?int?size);
        ????int?writen(const?char*?msg,?int?size);
        ????
        private:
        ????int?lfd;?//?監(jiān)聽(tīng)的套接字
        ????int?cfd;?//?通信的套接字
        };

        通過(guò)對(duì)服務(wù)器端的操作進(jìn)行封裝,我們可以看到這個(gè)類和客戶端的類結(jié)構(gòu)以及封裝思路是差不多的,并且兩個(gè)類的內(nèi)部有些操作的重疊的:接收和發(fā)送通信數(shù)據(jù)的函數(shù) recvMsg()、sendMsg(),以及內(nèi)部函數(shù) readn()、writen()。不僅如此服務(wù)器端的類設(shè)計(jì)成這樣樣子是有缺陷的:服務(wù)器端一般需要和多個(gè)客戶端建立連接,因此通信的套接字就需要有 N 個(gè),但是在上面封裝的類里邊只有一個(gè)

        既然如此,我們?nèi)绾谓鉀Q服務(wù)器和客戶端的代碼冗余和服務(wù)器不能跟多客戶端通信的問(wèn)題呢?

        答:瘦身、減負(fù)??梢詫⒎?wù)器的通信功能去掉,只留下監(jiān)聽(tīng)并建立新連接一個(gè)功能。將客戶端類變成一個(gè)專門用于套接字通信的類即可。服務(wù)器端整個(gè)流程使用服務(wù)器類 + 通信類來(lái)處理;客戶端整個(gè)流程通過(guò)通信的類來(lái)處理。

        2.2 版本 2

        根據(jù)對(duì)第一個(gè)版本的分析,可以對(duì)以上代碼做如下修改:

        2.2.1 通信類

        套接字通信類既可以在客戶端使用,也可以在服務(wù)器端使用,職責(zé)是接收和發(fā)送數(shù)據(jù)包。

        類聲明

        class?TcpSocket
        {
        public:
        ????TcpSocket();
        ????TcpSocket(int?socket);
        ????~TcpSocket();
        ????int?connectToHost(string?ip,?unsigned?short?port);
        ????int?sendMsg(string?msg);
        ????string?recvMsg();

        private:
        ????int?readn(char*?buf,?int?size);
        ????int?writen(const?char*?msg,?int?size);

        private:
        ????int?m_fd;?//?通信的套接字
        };

        類定義

        TcpSocket::TcpSocket()
        {
        ????m_fd?=?socket(AF_INET,?SOCK_STREAM,?0);
        }

        TcpSocket::TcpSocket(int?socket)
        {
        ????m_fd?=?socket;
        }

        TcpSocket::~TcpSocket()
        {
        ????if?(m_fd?>?0)
        ????{
        ????????close(m_fd);
        ????}
        }

        int?TcpSocket::connectToHost(string?ip,?unsigned?short?port)
        {
        ????//?連接服務(wù)器IP?port
        ????struct?sockaddr_in?saddr;
        ????saddr.sin_family?=?AF_INET;
        ????saddr.sin_port?=?htons(port);
        ????inet_pton(AF_INET,?ip.data(),?&saddr.sin_addr.s_addr);
        ????int?ret?=?connect(m_fd,?(struct?sockaddr*)&saddr,?sizeof(saddr));
        ????if?(ret?==?-1)
        ????{
        ????????perror("connect");
        ????????return?-1;
        ????}
        ????cout?<"成功和服務(wù)器建立連接..."?<????return?ret;
        }

        int?TcpSocket::sendMsg(string?msg)
        {
        ????//?申請(qǐng)內(nèi)存空間:?數(shù)據(jù)長(zhǎng)度?+?包頭4字節(jié)(存儲(chǔ)數(shù)據(jù)長(zhǎng)度)
        ????char*?data?=?new?char[msg.size()?+?4];
        ????int?bigLen?=?htonl(msg.size());
        ????memcpy(data,?&bigLen,?4);
        ????memcpy(data?+?4,?msg.data(),?msg.size());
        ????//?發(fā)送數(shù)據(jù)
        ????int?ret?=?writen(data,?msg.size()?+?4);
        ????delete[]data;
        ????return?ret;
        }

        string?TcpSocket::recvMsg()
        {
        ????//?接收數(shù)據(jù)
        ????//?1.?讀數(shù)據(jù)頭
        ????int?len?=?0;
        ????readn((char*)&len,?4);
        ????len?=?ntohl(len);
        ????cout?<"數(shù)據(jù)塊大小:?"?<
        ????//?根據(jù)讀出的長(zhǎng)度分配內(nèi)存
        ????char*?buf?=?new?char[len?+?1];
        ????int?ret?=?readn(buf,?len);
        ????if?(ret?!=?len)
        ????{
        ????????return?string();
        ????}
        ????buf[len]?=?'\0';
        ????string?retStr(buf);
        ????delete[]buf;

        ????return?retStr;
        }

        int?TcpSocket::readn(char*?buf,?int?size)
        {
        ????int?nread?=?0;
        ????int?left?=?size;
        ????char*?p?=?buf;

        ????while?(left?>?0)
        ????{
        ????????if?((nread?=?read(m_fd,?p,?left))?>?0)
        ????????{
        ????????????p?+=?nread;
        ????????????left?-=?nread;
        ????????}
        ????????else?if?(nread?==?-1)
        ????????{
        ????????????return?-1;
        ????????}
        ????}
        ????return?size;
        }

        int?TcpSocket::writen(const?char*?msg,?int?size)
        {
        ????int?left?=?size;
        ????int?nwrite?=?0;
        ????const?char*?p?=?msg;

        ????while?(left?>?0)
        ????{
        ????????if?((nwrite?=?write(m_fd,?msg,?left))?>?0)
        ????????{
        ????????????p?+=?nwrite;
        ????????????left?-=?nwrite;
        ????????}
        ????????else?if?(nwrite?==?-1)
        ????????{
        ????????????return?-1;
        ????????}
        ????}
        ????return?size;
        }

        在第二個(gè)版本的套接字通信類中一共有兩個(gè)構(gòu)造函數(shù):

        TcpSocket::TcpSocket()
        {
        ????m_fd?=?socket(AF_INET,?SOCK_STREAM,?0);
        }

        TcpSocket::TcpSocket(int?socket)
        {
        ????m_fd?=?socket;
        }
        • 其中無(wú)參構(gòu)造一般在客戶端使用,通過(guò)這個(gè)套接字對(duì)象再和服務(wù)器進(jìn)行連接,之后就可以通信了
        • 有參構(gòu)造主要在服務(wù)器端使用,當(dāng)服務(wù)器端得到了一個(gè)用于通信的套接字對(duì)象之后,就可以基于這個(gè)套接字直接通信,因此不需要再次進(jìn)行連接操作。

        2.2.2 服務(wù)器類

        服務(wù)器類主要用于套接字通信的服務(wù)器端,并且沒(méi)有通信能力,當(dāng)服務(wù)器和客戶端的新連接建立之后,需要通過(guò) TcpSocket 類的帶參構(gòu)造將通信的描述符包裝成一個(gè)通信對(duì)象,這樣就可以使用這個(gè)對(duì)象和客戶端通信了。

        類聲明

        class?TcpServer
        {
        public:
        ????TcpServer();
        ????~TcpServer();
        ????int?setListen(unsigned?short?port);
        ????TcpSocket*?acceptConn(struct?sockaddr_in*?addr?=?nullptr);

        private:
        ????int?m_fd;?//?監(jiān)聽(tīng)的套接字
        };

        類定義

        TcpServer::TcpServer()
        {
        ????m_fd?=?socket(AF_INET,?SOCK_STREAM,?0);
        }

        TcpServer::~TcpServer()
        {
        ????close(m_fd);
        }

        int?TcpServer::setListen(unsigned?short?port)
        {
        ????struct?sockaddr_in?saddr;
        ????saddr.sin_family?=?AF_INET;
        ????saddr.sin_port?=?htons(port);
        ????saddr.sin_addr.s_addr?=?INADDR_ANY;??//?0?=?0.0.0.0
        ????int?ret?=?bind(m_fd,?(struct?sockaddr*)&saddr,?sizeof(saddr));
        ????if?(ret?==?-1)
        ????{
        ????????perror("bind");
        ????????return?-1;
        ????}
        ????cout?<"套接字綁定成功,?ip:?"
        ????????<????????<",?port:?"?<
        ????ret?=?listen(m_fd,?128);
        ????if?(ret?==?-1)
        ????{
        ????????perror("listen");
        ????????return?-1;
        ????}
        ????cout?<"設(shè)置監(jiān)聽(tīng)成功..."?<
        ????return?ret;
        }

        TcpSocket*?TcpServer::acceptConn(sockaddr_in*?addr)
        {
        ????if?(addr?==?NULL)
        ????{
        ????????return?nullptr;
        ????}

        ????socklen_t?addrlen?=?sizeof(struct?sockaddr_in);
        ????int?cfd?=?accept(m_fd,?(struct?sockaddr*)addr,?&addrlen);
        ????if?(cfd?==?-1)
        ????{
        ????????perror("accept");
        ????????return?nullptr;
        ????}
        ????printf("成功和客戶端建立連接...\n");
        ????return?new?TcpSocket(cfd);
        }

        通過(guò)調(diào)整可以發(fā)現(xiàn),套接字服務(wù)器類功能更加單一了,這樣設(shè)計(jì)即解決了代碼冗余問(wèn)題,還能使這兩個(gè)類更容易維護(hù)。

        3. 測(cè)試代碼

        3.1 客戶端

        int?main()
        {
        ????//?1.?創(chuàng)建通信的套接字
        ????TcpSocket?tcp;

        ????//?2.?連接服務(wù)器IP?port
        ????int?ret?=?tcp.connectToHost("192.168.237.131",?10000);
        ????if?(ret?==?-1)
        ????{
        ????????return?-1;
        ????}

        ????//?3.?通信
        ????int?fd1?=?open("english.txt",?O_RDONLY);
        ????int?length?=?0;
        ????char?tmp[100];
        ????memset(tmp,?0,?sizeof(tmp));
        ????while?((length?=?read(fd1,?tmp,?sizeof(tmp)))?>?0)
        ????{
        ????????//?發(fā)送數(shù)據(jù)
        ????????tcp.sendMsg(string(tmp,?length));

        ????????cout?<"send?Msg:?"?<????????cout?<????????memset(tmp,?0,?sizeof(tmp));

        ????????//?接收數(shù)據(jù)
        ????????usleep(300);
        ????}

        ????sleep(10);

        ????return?0;
        }

        3.2 服務(wù)器端

        struct?SockInfo
        {
        ????TcpServer*?s;
        ????TcpSocket*?tcp;
        ????struct?sockaddr_in?addr;
        };

        void*?working(void*?arg)
        {
        ????struct?SockInfo*?pinfo?=?static_cast(arg);
        ????//?連接建立成功,?打印客戶端的IP和端口信息
        ????char?ip[32];
        ????printf("客戶端的IP:?%s,?端口:?%d\n",
        ????????inet_ntop(AF_INET,?&pinfo->addr.sin_addr.s_addr,?ip,?sizeof(ip)),
        ????????ntohs(pinfo->addr.sin_port));

        ????//?5.?通信
        ????while?(1)
        ????{
        ????????printf("接收數(shù)據(jù):?.....\n");
        ????????string?msg?=?pinfo->tcp->recvMsg();
        ????????if?(!msg.empty())
        ????????{
        ????????????cout?<????????}
        ????????else
        ????????{
        ????????????break;
        ????????}
        ????}
        ????delete?pinfo->tcp;
        ????delete?pinfo;
        ????return?nullptr;
        }

        int?main()
        {
        ????//?1.?創(chuàng)建監(jiān)聽(tīng)的套接字
        ????TcpServer?s;
        ????//?2.?綁定本地的IP?port并設(shè)置監(jiān)聽(tīng)
        ????s.setListen(10000);
        ????//?3.?阻塞并等待客戶端的連接
        ????while?(1)
        ????{
        ????????SockInfo*?info?=?new?SockInfo;
        ????????TcpSocket*?tcp?=?s.acceptConn(&info->addr);
        ????????if?(tcp?==?nullptr)
        ????????{
        ????????????cout?<"重試...."?<????????????continue;
        ????????}
        ????????//?創(chuàng)建子線程
        ????????pthread_t?tid;
        ????????info->s?=?&s;
        ????????info->tcp?=?tcp;

        ????????pthread_create(&tid,?NULL,?working,?info);
        ????????pthread_detach(tid);
        ????}

        ????return?0;
        }

        文章來(lái)源:https://subingwen.com/linux/socket-class/

        瀏覽 56
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            强开小嫩苞精品一区二区 | 国产美女精品人人做人人爽 | 亚洲色图另类图片 | 先锋影音男人资源 | 黄片免费视频在线 | 国产日韩欧美激情91在线 | www.亚洲成人 | 黄色片视频在线观看 | 人人插人人爱 | 欧美熟妇性又伦-区二区 |