溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何進(jìn)行TCP通信實(shí)現(xiàn)

發(fā)布時(shí)間:2021-11-17 14:36:09 來(lái)源:億速云 閱讀:170 作者:柒染 欄目:軟件技術(shù)

本篇文章給大家分享的是有關(guān)如何進(jìn)行TCP通信實(shí)現(xiàn),小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

TCP是底層通訊協(xié)議,定義的是數(shù)據(jù)傳輸和連接方式的規(guī)范。TCP協(xié)議,傳輸控制協(xié)議(Transmission Control Protocol,縮寫為:TCP)是一種面向連接的、可靠的、基于字節(jié)流的通信協(xié)議。講到TCP協(xié)議就繞不開(kāi)套接字Socket。這也是搞軟件開(kāi)發(fā)經(jīng)常接觸的技術(shù)點(diǎn)。 套接字Socket是通信的基石,是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本操作單元。它是網(wǎng)絡(luò)通信過(guò)程中端點(diǎn)的抽象表示,包含進(jìn)行網(wǎng)絡(luò)通信必須的五種信息:連接使用的協(xié)議,本地主機(jī)的IP地址,本地進(jìn)程的協(xié)議端口,遠(yuǎn)地主機(jī)的IP地址,遠(yuǎn)地進(jìn)程的協(xié)議端口。 創(chuàng)建Socket連接時(shí),可以指定使用的傳輸層協(xié)議,Socket可以支持不同的傳輸層協(xié)議(TCP或UDP),當(dāng)使用TCP協(xié)議進(jìn)行連接時(shí),該Socket連接就是一個(gè)TCP連接。

在網(wǎng)絡(luò)通訊中,從架構(gòu)設(shè)計(jì)和應(yīng)用需要具備抽象思維。讓閱讀者和使用者非常清晰的理解設(shè)計(jì)思路。采用割裂思維。形象的比喻成大炮和炮彈。大炮。發(fā)射裝置分HTTP和TCP。收發(fā)機(jī)制不同。每種編程語(yǔ)言都有自己固定的API實(shí)現(xiàn)。炮彈就是二進(jìn)制流數(shù)據(jù)。不固定完全可以DIY。就是我們常說(shuō)的通信協(xié)議。所謂“協(xié)議”是雙方共同遵守的規(guī)則。協(xié)議有語(yǔ)法、語(yǔ)義、時(shí)序三要素。炮彈抽象轉(zhuǎn)實(shí)體就是Gk8ByteMaker。具體實(shí)現(xiàn)參閱。 網(wǎng)絡(luò)通信1:字節(jié)流的封裝。針對(duì)大炮發(fā)射裝置實(shí)現(xiàn)。其實(shí)許多編程語(yǔ)言都不需要自己造輪子。甚至很多框架支持、比如Java有名氣的MINA框架。作為編程者應(yīng)該需要探索的欲望。自己實(shí)現(xiàn)過(guò)對(duì)底層的理解更透徹。領(lǐng)悟過(guò)記憶才更深刻。曾經(jīng)有個(gè)面試者就理直氣壯說(shuō)Socket底層就是可以直接傳輸類對(duì)象。因?yàn)樗ぷ鹘佑|的都是完善的框架。直接面向?qū)ο缶幊?。缺乏捅破窗戶紙窺探下底層真正的實(shí)現(xiàn)原理。

項(xiàng)目使用C++實(shí)現(xiàn)網(wǎng)絡(luò)TCP通信(tcpnet)。其中Gk8Socket是實(shí)現(xiàn)底層Socket通信。Gk8TcpService是提供接口服務(wù)。方便使用者方便快捷的使用。同時(shí)發(fā)射裝置肯定需要炮彈。也使用了Gk8ByteMaker。每種編程語(yǔ)言實(shí)現(xiàn)都有差異。這里僅拋磚引玉。重點(diǎn)還是理解思維和原理。記憶容易忘記。思維不容易忘記。

C++實(shí)現(xiàn)網(wǎng)絡(luò)Socket類:Gk8Socket.h

#ifndef _GK8SOCKET_H_
#define _GK8SOCKET_H_
#pragma once
#include "Gk8Env.h"
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    #include <winsock2.h>
    typedef int                socklen_t;
#else
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    typedef int                SOCKET;
    //[定義一些創(chuàng)建標(biāo)記宏]
    #define INVALID_SOCKET    -1
    #define SOCKET_ERROR    -1
#endif
class Gk8Socket
{
protected://[類保護(hù)屬性]
    SOCKET m_iSocket;        //[SCOKET套接字]
    fd_set m_fdR;            //[SCOKET信息]
public://[類公共屬性]
    Gk8Socket(SOCKET iSocket=INVALID_SOCKET);
    ~Gk8Socket();
    static int Init();
    static int Clean();
    Gk8Socket& operator=(SOCKET iSocket);
    operator SOCKET();
    bool Create(int af, int type, int protocol = 0);
    bool Connect(const char* ip, unsigned short port);
    bool Bind(unsigned short port);
    bool Listen(int backlog = 5);
    bool Accept(Gk8Socket& s, char* fromip = NULL);
    int Select();
    int Send(const char* buf, int len, int flags=0);
    int Recv(char* buf, int len, int flags=0);
    int Close();
    int GetError();
};
#endif

C++實(shí)現(xiàn)網(wǎng)絡(luò)Socket類:Gk8Socket.cpp

#include "Gk8Socket.h"
#include "Gk8OperSys.h"
#include <stdio.h>
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
#pragma comment(lib, "wsock32")
#endif
Gk8Socket::Gk8Socket(SOCKET iSocket)
{
    m_iSocket=iSocket;
}
Gk8Socket::~Gk8Socket()
{
}
//[初始化SOCKET]
int Gk8Socket::Init()
{
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    WSADATA wsaData;
    WORD version = MAKEWORD(2, 0);
    int nRet = WSAStartup(version, &wsaData);//[WinSock啟動(dòng)]
    if(nRet)
    {
        _GK8ERR<<"Initilize winsock error !"<<CR;
        return -1;
    }
#endif
    return 0;
}
//[清理SOCKET]
int Gk8Socket::Clean()
{
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    return (WSACleanup());
#endif
    return 0;
}
Gk8Socket& Gk8Socket::operator=(SOCKET iSocket)
{
    m_iSocket=iSocket;
    return (*this);
}
Gk8Socket::operator SOCKET()
{
    return m_iSocket;
}
//[創(chuàng)建套接字]
bool Gk8Socket::Create(int af, int type,int protocol)
{
    m_iSocket=socket(af, type, protocol);
    if(m_iSocket==INVALID_SOCKET)
    {
        return false;
    }
    return true;
}
//[連接SOCKET]
bool Gk8Socket::Connect(const char* ip,unsigned short port)
{
    struct sockaddr_in svraddr;
    svraddr.sin_family = AF_INET;
    svraddr.sin_addr.s_addr = inet_addr(ip);
    svraddr.sin_port = htons(port);
    int ret=connect(m_iSocket,(struct sockaddr*)&svraddr,sizeof(svraddr));
    if (ret==SOCKET_ERROR)
    {
        return false;
    }
    return true;
}
//[綁定端口]
bool Gk8Socket::Bind(unsigned short port)
{
    struct sockaddr_in svraddr;
    svraddr.sin_family = AF_INET;
    svraddr.sin_addr.s_addr = INADDR_ANY;
    svraddr.sin_port = htons(port);
    int opt = 1;
    if (setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))< 0)
        return false;
    int ret = bind(m_iSocket,(struct sockaddr*)&svraddr,sizeof(svraddr));
    if (ret==SOCKET_ERROR)
    {
        return false;
    }
    return true;
}
//[服務(wù)器監(jiān)聽(tīng)端口]
bool Gk8Socket::Listen(int backlog)
{
    int ret = listen(m_iSocket, backlog);
    if (ret == SOCKET_ERROR)
    {
        return false;
    }
    return true;
}
//[服務(wù)器接受套接字]
bool Gk8Socket::Accept(Gk8Socket& s,char* fromip)
{
    struct sockaddr_in cliaddr;
    socklen_t addrlen = sizeof(cliaddr);
    SOCKET sock = accept(m_iSocket,(struct sockaddr*)&cliaddr,&addrlen);
    if(sock == SOCKET_ERROR)
    {
        return false;
    }
    s=sock;
    if (fromip != NULL)
        sprintf(fromip, "%s", inet_ntoa(cliaddr.sin_addr));
    return true;
}
int Gk8Socket::Select()
{
    FD_ZERO(&m_fdR);
    FD_SET(m_iSocket,&m_fdR);
    struct timeval mytimeout;
    mytimeout.tv_sec=3;
    mytimeout.tv_usec=0;
    int result=select(m_iSocket+1,&m_fdR,NULL,NULL,NULL);
    //[第一個(gè)參數(shù)是0和sockfd中的最大值加一]
    //[第二個(gè)參數(shù)是讀集,也就是sockset]
    //[第三,四個(gè)參數(shù)是寫集和異常集,在本程序中都為空]
    //[第五個(gè)參數(shù)是超時(shí)時(shí)間,即在指定時(shí)間內(nèi)仍沒(méi)有可讀,則出錯(cuò)]
    if(result==-1)
    {
        return -1;
    }else
    {
        if(FD_ISSET(m_iSocket,&m_fdR)>0)
        {
            return -2;
        }else
        {
            return -3;
        }
    }
}
//[發(fā)送數(shù)據(jù):直接發(fā)送]
int Gk8Socket::Send(const char* buf, int len, int flags)
{
    int bytes;
    int count = 0;
    while(count<len)
    {
        bytes=(GK8_INT)send(m_iSocket,buf+count,len-count,flags);
        if(bytes==-1||bytes==0) return -1;
        count+=bytes;
    }
    return count;
}
//[接受數(shù)據(jù)]
int Gk8Socket::Recv(char* buf, int len, int flags)
{
    return (GK8_INT)recv(m_iSocket,buf,len,flags);
}
//[關(guān)閉SOCKET]
int Gk8Socket::Close()
{
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    return (closesocket(m_iSocket));
#else
    return (close(m_iSocket));
#endif
}
//[獲取錯(cuò)誤信息]
int Gk8Socket::GetError()
{
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    return (WSAGetLastError());
#else
    return -1;
#endif
}

C++實(shí)現(xiàn)Tcp服務(wù)類:Gk8TcpService.h

#ifndef __GK8TCPSERVICE_H__
#define __GK8TCPSERVICE_H__
#pragma once
#include "Gk8Socket.h"
#include "Gk8BaseObj.h"
#include "Gk8ByteMaker.h"
#include <pthread.h>
#include <semaphore.h>
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_IOS||GK8_TARGET_PLATFORM==GK8_PLATFORM_ANDROID)
#include <sys/time.h>
#endif
class Gk8TcpService:public Gk8BaseObj
{
    DECLARE_TOSPP_MAP;
private:
    pthread_t m_nPId;                    //[線程ID]
    GK8_BOOL m_bCreatePthread;            //[創(chuàng)建了線程]
    Gk8ByteMaker m_iRequestData;        //[TCP請(qǐng)求數(shù)據(jù)]
public:
    Gk8Socket m_iSocket;
    Gk8Str m_iHostIpStr;                //[服務(wù)器IP]
    GK8_INT m_nPort;                    //[服務(wù)端口]
    pthread_mutex_t mt_TcpResponseMutex;//[TCP響應(yīng)互斥體]
    Gk8ByteMaker m_iTcpData;            //[TCP反饋數(shù)據(jù)]
private:
    static void* start_thread(void*);    //[靜態(tài)成員函數(shù),相當(dāng)于C中的全局函數(shù)]
    GK8_VOID TcpSocketFailCallBack(GK8_INT nFailCode);
    GK8_VOID TcpSocketSuccCallBack();
    GK8_VOID TcpRequestStarted();
    GK8_VOID DispatcherReceiveMessage();
public:
    Gk8TcpService();
    ~Gk8TcpService();
    GK8_BOOL TOSPPFUNC Build(GK8_LPCSTR lpHostIp,GK8_INT nPort);
    GK8_VOID TOSPPFUNC SendMessage(Gk8ByteMaker* pRequestData);
    GK8_VOID TOSPPFUNC PutMessage(Gk8ByteMaker* pRequestData);
    GK8_VOID TOSPPFUNC SendCachedMessage();
    GK8_VOID TOSPPFUNC Close();            //[函數(shù)中止當(dāng)前線程]
    static GK8_VOID TcpClientTick();
};
#endif

C++實(shí)現(xiàn)Tcp服務(wù)類:Gk8TcpService.cpp

#include "Gk8TcpService.h"
//[TCP SOCKET錯(cuò)誤編碼]
enum TCPSOCKETFAILERRORCODE
{
    TCPCODE_PTHREAD_FAIL=0,
    TCPCODE_SOCKET_INIT_FAIL,
    TCPCODE_SOCKET_CREATE_FAIL,
    TCPCODE_SOCKET_CONNECT_FAIL,
    TCPCODE_SOCKET_SEND_FAIL,
    TCPCODE_END
};
static Gk8Var sg_iTcpSocketFailEventFun("OnTcpSocketFail");        //[TCPSOCKET失敗信息]
static Gk8Var sg_iTcpSocketSuccEventFun("OnTcpSocketSucc");        //[TCPSOCKET成功信息]
static Gk8Var sg_iTcpReceiveMessageFun("ReceiveMessage");        //[接收網(wǎng)絡(luò)信息]
static Gk8SortMap sg_iTcpSocketMap;                                //[委托MAP]//[用來(lái)管理回調(diào)的]
/////////////////////////////////////////////CLASS-TOSPP////////////////////////////////////////////////////
BEGIN_TOSPP_MAP(Gk8TcpService,Gk8BaseObj)
    TOSPP_FUNC(Gk8TcpService,Build,'b',"sd","Build(lpHostIp,nPort)")
    TOSPP_FUNC(Gk8TcpService,SendMessage,' ',"p","SendMessage(iRequestDataPtr)")
    TOSPP_FUNC(Gk8TcpService,PutMessage,' ',"p","PutMessage(iRequestDataPtr)")
    TOSPP_FUNC(Gk8TcpService,SendCachedMessage,' '," ","SendCachedMessage()")
    TOSPP_FUNC(Gk8TcpService,Close,' ',"","Close()")
END_TOSPP_MAP()
/////////////////////////////////////[套接字邏輯]///////////////////////////////////////////////
Gk8TcpService::Gk8TcpService()
{
    pthread_mutex_init(&mt_TcpResponseMutex,NULL);
    sg_iTcpSocketMap.AddItem((GK8_PTR_TYPE)this,0);
    m_bCreatePthread=false;
}
Gk8TcpService::~Gk8TcpService()
{
    pthread_mutex_destroy(&mt_TcpResponseMutex);
    sg_iTcpSocketMap.RemoveItem((GK8_PTR_TYPE)this);
}
//[套接字失敗回調(diào)]
GK8_VOID Gk8TcpService::TcpSocketFailCallBack(GK8_INT nFailCode)
{
    OnCall(sg_iTcpSocketFailEventFun,Gk8Var()<<nFailCode);
}
//[套接字成功回調(diào)]
GK8_VOID Gk8TcpService::TcpSocketSuccCallBack()
{
    OnCall(sg_iTcpSocketSuccEventFun);
}
//[創(chuàng)建套接字并連接.啟動(dòng)套接字線程]
GK8_BOOL Gk8TcpService::Build(GK8_LPCSTR lpHostIp,GK8_INT nPort)
{
    m_iRequestData.Destroy();
    m_iTcpData.Destroy();
    m_iHostIpStr=lpHostIp;
    m_nPort=nPort;
    int errCode=0;
    do
    {
        pthread_attr_t tAttr;
        errCode=pthread_attr_init(&tAttr);
        if(errCode!=0) return false;
        //[但是上面這個(gè)函數(shù)其他內(nèi)容則主要為你創(chuàng)建的線程設(shè)定為分離式]
        errCode=pthread_attr_setdetachstate(&tAttr,PTHREAD_CREATE_DETACHED);
        if(errCode!=0)
        {
            pthread_attr_destroy(&tAttr);
            TcpSocketFailCallBack(TCPCODE_PTHREAD_FAIL);
            return false;
        }
        m_bCreatePthread=true;
        errCode=pthread_create(&m_nPId,&tAttr,start_thread,this);
        if(errCode!=0)
        {
            pthread_attr_destroy(&tAttr);
            TcpSocketFailCallBack(TCPCODE_PTHREAD_FAIL);
            return false;
        }
    }while(0);
    return true;
}
//[套接字線程對(duì)象]
void* Gk8TcpService::start_thread(void* arg)
{
    Gk8TcpService* pTcpService=(Gk8TcpService*)arg;
    //[0表示連接成功.1表示連接失敗]
    Gk8Socket iSocket;
    if(iSocket.Init()!=0)
    {
        pTcpService->TcpSocketFailCallBack(TCPCODE_SOCKET_INIT_FAIL);
        return NULL;
    }
    //[創(chuàng)建套接字]
    if(!iSocket.Create(AF_INET,SOCK_STREAM,0))
    {
        pTcpService->TcpSocketFailCallBack(TCPCODE_SOCKET_CREATE_FAIL);
        return NULL;
    }
    //[連接套接字]
    if(!iSocket.Connect(pTcpService->m_iHostIpStr,pTcpService->m_nPort))
    {
        pTcpService->TcpSocketFailCallBack(TCPCODE_SOCKET_CONNECT_FAIL);
        return NULL;
    }
    pTcpService->m_iSocket=iSocket;
    //[通知連接成功]
    pTcpService->TcpSocketSuccCallBack();
    //[循環(huán)監(jiān)聽(tīng).接收數(shù)據(jù)]
    Gk8ByteMaker sl_iRecvBuf;
    sl_iRecvBuf.WriteAlloc(1024*1024);
    GK8_INT nRecvLen=0;
    while(true)
    {
        //[表示服務(wù)器端有消息推送過(guò)來(lái).會(huì)接受HTTP的請(qǐng)求返回]
        if(iSocket.Select()==-2)
        {
            sl_iRecvBuf.ClearStream();
            nRecvLen=iSocket.Recv((GK8_LPSTR)sl_iRecvBuf.GetBuf(),1024*1024,0);
            if(nRecvLen<=0) continue;
            //[多線程控制]
            pthread_mutex_lock(&pTcpService->mt_TcpResponseMutex);
            pTcpService->m_iTcpData.WriteBuf(sl_iRecvBuf.GetBuf(),nRecvLen);
            pthread_mutex_unlock(&pTcpService->mt_TcpResponseMutex);
        }
    }
    return NULL;
}
//[發(fā)送消息]
GK8_VOID Gk8TcpService::SendMessage(Gk8ByteMaker* pRequestData)
{
    pRequestData->ShiftTo(m_iRequestData);
    TcpRequestStarted();
}
//[把二進(jìn)制流重組成新的對(duì)象]
GK8_VOID Gk8TcpService::PutMessage(Gk8ByteMaker* pRequestData)
{
    pRequestData->ShiftTo(m_iRequestData);
}
GK8_VOID Gk8TcpService::SendCachedMessage()
{
    TcpRequestStarted();
}
//[開(kāi)始TCP請(qǐng)求]
GK8_VOID Gk8TcpService::TcpRequestStarted()
{
    GK8_INT nSendLen=m_iRequestData.GetStreamSize();
    if(m_iSocket.Send((GK8_LPCSTR)m_iRequestData.GetBuf(),nSendLen)!=nSendLen)
    {
        TcpSocketFailCallBack(TCPCODE_SOCKET_SEND_FAIL);
        return ;
    }
    m_iRequestData.ClearStream();
}
//[向腳本派發(fā)消息]
GK8_VOID Gk8TcpService::DispatcherReceiveMessage()
{
    if(m_iTcpData.GetStreamSize()<2*sizeof(GK8_WORD)) return;
    pthread_mutex_lock(&mt_TcpResponseMutex);
    Gk8Var iByteMakerVar(&m_iTcpData,m_iTcpData.GetObjId());
    OnCall(sg_iTcpReceiveMessageFun,iByteMakerVar);
    //[把數(shù)據(jù)往前提]
    m_iTcpData.Pack();
    pthread_mutex_unlock(&mt_TcpResponseMutex);
}
//[停止SOCKET]
GK8_VOID Gk8TcpService::Close()
{
    m_iSocket.Close();
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_ANDROID)
    _GK8ERR<<"Close"<<CR;
    pthread_detach(m_nPId);
#endif
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_IOS)
    pthread_cancel(m_nPId);
    pthread_detach(m_nPId);
#endif
#if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32)
    if(m_bCreatePthread)
    {
        m_bCreatePthread=false;
        pthread_cancel(m_nPId);
        pthread_detach(m_nPId);
        pthread_join(m_nPId,NULL);
    }
#endif
    pthread_mutex_lock(&mt_TcpResponseMutex);
    m_iRequestData.Destroy();
    m_iTcpData.Destroy();
    pthread_mutex_unlock(&mt_TcpResponseMutex);
}
//[TCP客戶端檢測(cè)]
GK8_VOID Gk8TcpService::TcpClientTick()
{
    Gk8TcpService* pTcpService=NULL;
    for(GK8_INT i=0;i<sg_iTcpSocketMap.GetSize();i++)
    {
        pTcpService=(Gk8TcpService*)sg_iTcpSocketMap.GetItemIdAt(i);
        pTcpService->DispatcherReceiveMessage();
    }
}

以上就是如何進(jìn)行TCP通信實(shí)現(xiàn),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

tcp
AI