您的位置:首页 > 编程语言 > C语言/C++

c++ socket封包接收发送

2018-03-09 21:35 2291 查看
拆包接收数据
class AfTcpRecv
{
public:
AfTcpRecv(AfSocket sock) :sock(sock)
{
BUFSIZE = 128 * 1024;
data = new char[BUFSIZE];
}

~AfTcpRecv()
{
delete[] data;
}

void clear()
{
type = 0;
length = 0;
}
// 接收一个完整分包 
// 返回值: >=0时,表示接收到的数据长度(可以为0)
// <0时,表示接收出错
int recv()
{
// 接收头部 
unsigned char header[4];
if (4 != sock.ReadExact((char*)header, 4))
{
return -11; // 接收head部分出错
}

// 接收数据部分
this->type = getUint16(header);
this->length = getUint16(header + 2);
if (length > BUFSIZE)
{
return -12; // 数据过长
}

// 数据部分是0个字节
if (length == 0)
return 0;

// 
int n = sock.ReadExact( data, length);
if (n != length)
{
return -13; // 接收data部分出错
}
data[length] = 0; // 末尾补0, 方便按C风格字符串处理
return n;
}

private:

// 按大端读取unsigned short
unsigned short  getUint16(unsigned char* buf)
{
return (buf[0] << 8) + buf[1];
}

public:
AfSocket sock;  // socket
int  BUFSIZE;          // 接收缓冲区大小
unsigned short type;   // 接收到的消息类型
unsigned short length; // 接收到的消息数据长度
char* data;            // 接收到的数据
};

发送数据的函数
int AfSocket::sendData(unsigned short type, unsigned short length, const void* data)
{
unsigned char header[4];
putUint16(header, type);
putUint16(header + 2, length);
SendExact(header, 4);  // 发送头部

if (length <= 0) return 0; // 数据部分是0个字节

return SendExact(data, length); // 发送数据部分
}

int AfSocket::SendExact(const void *pBuf, const unsigned int len)
{
if (!pBuf || len < 1)
{
return 0;
}
fd_set write_fds;
struct timeval tm;
int count;
unsigned int bytes_send = 0;
while (bytes_send < len)
{
do
{
FD_ZERO(&write_fds);
FD_SET(m_hSocket, &write_fds);
tm.tv_sec = 1;
tm.tv_usec = 0;
count = socket_select((int)m_hSocket, NULL, &write_fds, NULL, &tm);
} while (count == 0);

if (count != 1 || !FD_ISSET(m_hSocket, &write_fds))
return 0;

unsigned int portion_size = (unsigned int)(len - bytes_send);
if (portion_size > 32768)
portion_size = 32768;

int nBytes = ::send(m_hSocket, (const char*)pBuf + bytes_send, portion_size, 0);
if (nBytes > 0)
{
bytes_send += nBytes;
}
else if (SOCKET_ERROR == nBytes)
{
switch (WSAGetLastError())
{
case WSAEWOULDBLOCK:   // 套接字被阻塞
return bytes_send;
case WSAENETDOWN:   // 子网络系统失败
case WSAEINTR:     // SOCKET关闭
case WSAENOTCONN:  // 套接字没有连接
case WSAENOTSOCK:  // 描述符不是套接字
case WSAESHUTDOWN: // shutdown被调用
default:
return -1;
}
}
else
{
return bytes_send;
}
}
return bytes_send;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp socket