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;
}
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;
}
相关文章推荐
- C++ socket 循环发送,循环接收样例
- C语言重写网络发送/接收封包
- java利用httpconnect向服务器发送信息与接收回馈信息
- Scala:简单使用Actor的消息发送与接收求和
- Android之发送短信和接收验证码
- 基于openfire+smack开发Android即时聊天应用[四]-单人聊天、群聊、发送接收文件等
- STM32F10x_硬件I2C主从通信(轮询发送,中断接收)
- Android如何实现接收和发送短信
- RN发送接收事件--原生模块
- RabbitMQ之最简单的消息的发送与接收
- 网络协议栈14:Connect函数分解之网卡发送/接收数据流程
- PHP发送和接收POST数据
- STM32 USART 串口 DMA 接收和发送的源码详解!
- PHP主动发送与被动接收xml数据戎
- [033] 微信公众帐号开发教程第9篇-QQ表情的发送与接收 .
- 通过异步方式发送和接收数据(tcp异步收发数据)
- JavaMail发送和接收邮件
- 【EDM经验交流】之如何监控某个域名邮箱发送到网易的邮件接收情况?
- MFC - 文件发送接收
- 用Javamail写的邮件接收程序和发送程序