您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何進行TCP通信實現,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
TCP是底層通訊協議,定義的是數據傳輸和連接方式的規范。TCP協議,傳輸控制協議(Transmission Control Protocol,縮寫為:TCP)是一種面向連接的、可靠的、基于字節流的通信協議。講到TCP協議就繞不開套接字Socket。這也是搞軟件開發經常接觸的技術點。 套接字Socket是通信的基石,是支持TCP/IP協議的網絡通信的基本操作單元。它是網絡通信過程中端點的抽象表示,包含進行網絡通信必須的五種信息:連接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。 創建Socket連接時,可以指定使用的傳輸層協議,Socket可以支持不同的傳輸層協議(TCP或UDP),當使用TCP協議進行連接時,該Socket連接就是一個TCP連接。
在網絡通訊中,從架構設計和應用需要具備抽象思維。讓閱讀者和使用者非常清晰的理解設計思路。采用割裂思維。形象的比喻成大炮和炮彈。大炮。發射裝置分HTTP和TCP。收發機制不同。每種編程語言都有自己固定的API實現。炮彈就是二進制流數據。不固定完全可以DIY。就是我們常說的通信協議。所謂“協議”是雙方共同遵守的規則。協議有語法、語義、時序三要素。炮彈抽象轉實體就是Gk8ByteMaker。具體實現參閱。 網絡通信1:字節流的封裝。針對大炮發射裝置實現。其實許多編程語言都不需要自己造輪子。甚至很多框架支持、比如Java有名氣的MINA框架。作為編程者應該需要探索的欲望。自己實現過對底層的理解更透徹。領悟過記憶才更深刻。曾經有個面試者就理直氣壯說Socket底層就是可以直接傳輸類對象。因為他工作接觸的都是完善的框架。直接面向對象編程。缺乏捅破窗戶紙窺探下底層真正的實現原理。
項目使用C++實現網絡TCP通信(tcpnet)。其中Gk8Socket是實現底層Socket通信。Gk8TcpService是提供接口服務。方便使用者方便快捷的使用。同時發射裝置肯定需要炮彈。也使用了Gk8ByteMaker。每種編程語言實現都有差異。這里僅拋磚引玉。重點還是理解思維和原理。記憶容易忘記。思維不容易忘記。
C++實現網絡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; //[定義一些創建標記宏] #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #endif class Gk8Socket { protected://[類保護屬性] 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++實現網絡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啟動] 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; } //[創建套接字] 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; } //[服務器監聽端口] bool Gk8Socket::Listen(int backlog) { int ret = listen(m_iSocket, backlog); if (ret == SOCKET_ERROR) { return false; } return true; } //[服務器接受套接字] 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); //[第一個參數是0和sockfd中的最大值加一] //[第二個參數是讀集,也就是sockset] //[第三,四個參數是寫集和異常集,在本程序中都為空] //[第五個參數是超時時間,即在指定時間內仍沒有可讀,則出錯] if(result==-1) { return -1; }else { if(FD_ISSET(m_iSocket,&m_fdR)>0) { return -2; }else { return -3; } } } //[發送數據:直接發送] 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; } //[接受數據] int Gk8Socket::Recv(char* buf, int len, int flags) { return (GK8_INT)recv(m_iSocket,buf,len,flags); } //[關閉SOCKET] int Gk8Socket::Close() { #if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32) return (closesocket(m_iSocket)); #else return (close(m_iSocket)); #endif } //[獲取錯誤信息] int Gk8Socket::GetError() { #if(GK8_TARGET_PLATFORM==GK8_PLATFORM_WIN32) return (WSAGetLastError()); #else return -1; #endif }
C++實現Tcp服務類: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; //[創建了線程] Gk8ByteMaker m_iRequestData; //[TCP請求數據] public: Gk8Socket m_iSocket; Gk8Str m_iHostIpStr; //[服務器IP] GK8_INT m_nPort; //[服務端口] pthread_mutex_t mt_TcpResponseMutex;//[TCP響應互斥體] Gk8ByteMaker m_iTcpData; //[TCP反饋數據] private: static void* start_thread(void*); //[靜態成員函數,相當于C中的全局函數] 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(); //[函數中止當前線程] static GK8_VOID TcpClientTick(); }; #endif
C++實現Tcp服務類:Gk8TcpService.cpp
#include "Gk8TcpService.h" //[TCP SOCKET錯誤編碼] 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"); //[接收網絡信息] static Gk8SortMap sg_iTcpSocketMap; //[委托MAP]//[用來管理回調的] /////////////////////////////////////////////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); } //[套接字失敗回調] GK8_VOID Gk8TcpService::TcpSocketFailCallBack(GK8_INT nFailCode) { OnCall(sg_iTcpSocketFailEventFun,Gk8Var()<<nFailCode); } //[套接字成功回調] GK8_VOID Gk8TcpService::TcpSocketSuccCallBack() { OnCall(sg_iTcpSocketSuccEventFun); } //[創建套接字并連接.啟動套接字線程] 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; //[但是上面這個函數其他內容則主要為你創建的線程設定為分離式] 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; } //[套接字線程對象] 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; } //[創建套接字] 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(); //[循環監聽.接收數據] Gk8ByteMaker sl_iRecvBuf; sl_iRecvBuf.WriteAlloc(1024*1024); GK8_INT nRecvLen=0; while(true) { //[表示服務器端有消息推送過來.會接受HTTP的請求返回] 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; } //[發送消息] GK8_VOID Gk8TcpService::SendMessage(Gk8ByteMaker* pRequestData) { pRequestData->ShiftTo(m_iRequestData); TcpRequestStarted(); } //[把二進制流重組成新的對象] GK8_VOID Gk8TcpService::PutMessage(Gk8ByteMaker* pRequestData) { pRequestData->ShiftTo(m_iRequestData); } GK8_VOID Gk8TcpService::SendCachedMessage() { TcpRequestStarted(); } //[開始TCP請求] 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(); } //[向腳本派發消息] 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); //[把數據往前提] 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客戶端檢測] 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(); } }
以上就是如何進行TCP通信實現,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。