首页 网络技术
  1. 正文

如何进行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#endifclass 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")#endifGk8Socket::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>#endifclass 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通信实现
本文链接:https://www.qqooo.cn/post/5035.html
版权说明:网站文章均来源于手工整理和网友投稿,若有不妥之处请来信 xsds@vip.qq.com 处理,谢谢!