11 个解决方案
#1
处理好粘包问题就不会出错了。
QQ: 84162092
QQ: 84162092
#2
4K有些大吧,1K试试。
#3
你按顺序发的话是不会有问题的,需要注意几点
1。客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
2。分块不要分得太大,最好控制在1K左右
3。如果必要,可以采用 数据报长度+数据报内容来防止拈包
1。客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
2。分块不要分得太大,最好控制在1K左右
3。如果必要,可以采用 数据报长度+数据报内容来防止拈包
#4
谢谢大,如何处理这个问题
jebbthe(青苹果)
如果保证 客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
是使用数据报长度+数据报内容 =1K吗?
jebbthe(青苹果)
如果保证 客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
是使用数据报长度+数据报内容 =1K吗?
#5
发送端缓冲满了,而导致数据出错吧?
#6
我设置为1k还是不行,有和我相同问题的人吗
#7
除非在局域网,否则连续发送包肯定数据错乱
#8
1.系统支持的最大的数据报你可以调用GetSockOpt来获得,我说的1K指的就是系统支持的最大的数据报长度。
2.一定得记得判断send的结果,很多粗心的程序员会忽略这点。
3. 确定你的程序到底是发送端有问题还是接收方有问题,我更怀疑是你的接收方可能有bug。
4.还是那个粘包问题,我不知道你的程序机制是怎么样的,会不会有这个问题得由你自己来判断了:)
2.一定得记得判断send的结果,很多粗心的程序员会忽略这点。
3. 确定你的程序到底是发送端有问题还是接收方有问题,我更怀疑是你的接收方可能有bug。
4.还是那个粘包问题,我不知道你的程序机制是怎么样的,会不会有这个问题得由你自己来判断了:)
#9
我也是有这种情况 采用将数据限制在1K也不行 也是苦恼的不行
#10
你是编程思路不对,把流格式的的TCP当成数据包格式的UDP来用了,一般做法是这样(写代码比较直观):
struct packet_t
{
int len;
int cmd;
char data[1];
};
class peer_t
{
....
// 两个缓存区,其中 buffer_t 是自增长
buffer_t m_recvbuffer;
buffer_t m_sendbuffer;
bool is_alive();
void stop();
void on_read();
void on_write()
{
handle_sendbuffer();
}
...
void send_data(void* data, int len)
{
// 都先放到发送缓存区
m_sendbuffer.write(data, len);
handle_sendbuffer();
}
void handle_recvbuffer();
void handle_sendbuffer();
};
peer_t::on_read()
{
char buf[4096];
int recv_len = recv(....buf, sizeof(buf));
if (recv_len > 0)
{
// 不管3721,都接收回缓存区再说,然后从缓存区去数据处理
m_recvbuffer.write(buf, recv_len);
handle_recvbuffer();
} else if ...
}
peer_t::handle_recvbuffer()
{
while (is_alive())
{
char* recv_buf = m_recvbuffer.buffer();
int recv_len = m_recvbuffer.length();
packet_t* packet = (packet_t*) recv_buf;
// 检查是否收够完整的一个包
if (recv_len < 4 /* sizeof(packet_t.len) */) break;
if (packet->len > MAX_PACKET_SIZE)
{
// 太大的包,可能是攻击包,或错误的包,不接受
stop();
break;
}
if (recv_len < 4 + packet->len) break;
// 处理一个包
process_packet(packet);
// 把已处理的包清除出缓存区
m_recvbuffer.descard(4 + packet->len);
}
}
peer_t::handle_sendbuffer()
{
while (is_alive())
{
char* buf_ptr = m_sendbuffer.buffer();
int buf_len = m_sendbuffer.length();
if (buf_len < 1) break;
// 尽量发,能发多少就多少,剩下的下次再发
int send_len = send(...buf_ptr, buf_len);
if (send_len > 0)
{
// 把已发的清除出缓存区
m_sendbuffer.descard(send_len);
} else if ....
}
}
当然如果你是发送文件,一般做法是先发一个包头,然后源源不断的发文件数据,那就是另一个做法了,因为上面的代码是最起码收完一个完整包到缓存区才分析运作,而且限制了最大包头长度。稍为改一下就可以。
struct packet_t
{
int len;
int cmd;
char data[1];
};
class peer_t
{
....
// 两个缓存区,其中 buffer_t 是自增长
buffer_t m_recvbuffer;
buffer_t m_sendbuffer;
bool is_alive();
void stop();
void on_read();
void on_write()
{
handle_sendbuffer();
}
...
void send_data(void* data, int len)
{
// 都先放到发送缓存区
m_sendbuffer.write(data, len);
handle_sendbuffer();
}
void handle_recvbuffer();
void handle_sendbuffer();
};
peer_t::on_read()
{
char buf[4096];
int recv_len = recv(....buf, sizeof(buf));
if (recv_len > 0)
{
// 不管3721,都接收回缓存区再说,然后从缓存区去数据处理
m_recvbuffer.write(buf, recv_len);
handle_recvbuffer();
} else if ...
}
peer_t::handle_recvbuffer()
{
while (is_alive())
{
char* recv_buf = m_recvbuffer.buffer();
int recv_len = m_recvbuffer.length();
packet_t* packet = (packet_t*) recv_buf;
// 检查是否收够完整的一个包
if (recv_len < 4 /* sizeof(packet_t.len) */) break;
if (packet->len > MAX_PACKET_SIZE)
{
// 太大的包,可能是攻击包,或错误的包,不接受
stop();
break;
}
if (recv_len < 4 + packet->len) break;
// 处理一个包
process_packet(packet);
// 把已处理的包清除出缓存区
m_recvbuffer.descard(4 + packet->len);
}
}
peer_t::handle_sendbuffer()
{
while (is_alive())
{
char* buf_ptr = m_sendbuffer.buffer();
int buf_len = m_sendbuffer.length();
if (buf_len < 1) break;
// 尽量发,能发多少就多少,剩下的下次再发
int send_len = send(...buf_ptr, buf_len);
if (send_len > 0)
{
// 把已发的清除出缓存区
m_sendbuffer.descard(send_len);
} else if ....
}
}
当然如果你是发送文件,一般做法是先发一个包头,然后源源不断的发文件数据,那就是另一个做法了,因为上面的代码是最起码收完一个完整包到缓存区才分析运作,而且限制了最大包头长度。稍为改一下就可以。
#11
谢谢大家,我以解决这个问题,是接收端的问题,我的程序会处理拈包问题,所以不会在这个问题上,最后确定SOCKET的接收函数revc使用阻塞方式,要求收1024可是收了640就返回了,
#1
处理好粘包问题就不会出错了。
QQ: 84162092
QQ: 84162092
#2
4K有些大吧,1K试试。
#3
你按顺序发的话是不会有问题的,需要注意几点
1。客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
2。分块不要分得太大,最好控制在1K左右
3。如果必要,可以采用 数据报长度+数据报内容来防止拈包
1。客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
2。分块不要分得太大,最好控制在1K左右
3。如果必要,可以采用 数据报长度+数据报内容来防止拈包
#4
谢谢大,如何处理这个问题
jebbthe(青苹果)
如果保证 客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
是使用数据报长度+数据报内容 =1K吗?
jebbthe(青苹果)
如果保证 客户端要保证下一次发送数据前,前一次发送的数据已经成功送出
是使用数据报长度+数据报内容 =1K吗?
#5
发送端缓冲满了,而导致数据出错吧?
#6
我设置为1k还是不行,有和我相同问题的人吗
#7
除非在局域网,否则连续发送包肯定数据错乱
#8
1.系统支持的最大的数据报你可以调用GetSockOpt来获得,我说的1K指的就是系统支持的最大的数据报长度。
2.一定得记得判断send的结果,很多粗心的程序员会忽略这点。
3. 确定你的程序到底是发送端有问题还是接收方有问题,我更怀疑是你的接收方可能有bug。
4.还是那个粘包问题,我不知道你的程序机制是怎么样的,会不会有这个问题得由你自己来判断了:)
2.一定得记得判断send的结果,很多粗心的程序员会忽略这点。
3. 确定你的程序到底是发送端有问题还是接收方有问题,我更怀疑是你的接收方可能有bug。
4.还是那个粘包问题,我不知道你的程序机制是怎么样的,会不会有这个问题得由你自己来判断了:)
#9
我也是有这种情况 采用将数据限制在1K也不行 也是苦恼的不行
#10
你是编程思路不对,把流格式的的TCP当成数据包格式的UDP来用了,一般做法是这样(写代码比较直观):
struct packet_t
{
int len;
int cmd;
char data[1];
};
class peer_t
{
....
// 两个缓存区,其中 buffer_t 是自增长
buffer_t m_recvbuffer;
buffer_t m_sendbuffer;
bool is_alive();
void stop();
void on_read();
void on_write()
{
handle_sendbuffer();
}
...
void send_data(void* data, int len)
{
// 都先放到发送缓存区
m_sendbuffer.write(data, len);
handle_sendbuffer();
}
void handle_recvbuffer();
void handle_sendbuffer();
};
peer_t::on_read()
{
char buf[4096];
int recv_len = recv(....buf, sizeof(buf));
if (recv_len > 0)
{
// 不管3721,都接收回缓存区再说,然后从缓存区去数据处理
m_recvbuffer.write(buf, recv_len);
handle_recvbuffer();
} else if ...
}
peer_t::handle_recvbuffer()
{
while (is_alive())
{
char* recv_buf = m_recvbuffer.buffer();
int recv_len = m_recvbuffer.length();
packet_t* packet = (packet_t*) recv_buf;
// 检查是否收够完整的一个包
if (recv_len < 4 /* sizeof(packet_t.len) */) break;
if (packet->len > MAX_PACKET_SIZE)
{
// 太大的包,可能是攻击包,或错误的包,不接受
stop();
break;
}
if (recv_len < 4 + packet->len) break;
// 处理一个包
process_packet(packet);
// 把已处理的包清除出缓存区
m_recvbuffer.descard(4 + packet->len);
}
}
peer_t::handle_sendbuffer()
{
while (is_alive())
{
char* buf_ptr = m_sendbuffer.buffer();
int buf_len = m_sendbuffer.length();
if (buf_len < 1) break;
// 尽量发,能发多少就多少,剩下的下次再发
int send_len = send(...buf_ptr, buf_len);
if (send_len > 0)
{
// 把已发的清除出缓存区
m_sendbuffer.descard(send_len);
} else if ....
}
}
当然如果你是发送文件,一般做法是先发一个包头,然后源源不断的发文件数据,那就是另一个做法了,因为上面的代码是最起码收完一个完整包到缓存区才分析运作,而且限制了最大包头长度。稍为改一下就可以。
struct packet_t
{
int len;
int cmd;
char data[1];
};
class peer_t
{
....
// 两个缓存区,其中 buffer_t 是自增长
buffer_t m_recvbuffer;
buffer_t m_sendbuffer;
bool is_alive();
void stop();
void on_read();
void on_write()
{
handle_sendbuffer();
}
...
void send_data(void* data, int len)
{
// 都先放到发送缓存区
m_sendbuffer.write(data, len);
handle_sendbuffer();
}
void handle_recvbuffer();
void handle_sendbuffer();
};
peer_t::on_read()
{
char buf[4096];
int recv_len = recv(....buf, sizeof(buf));
if (recv_len > 0)
{
// 不管3721,都接收回缓存区再说,然后从缓存区去数据处理
m_recvbuffer.write(buf, recv_len);
handle_recvbuffer();
} else if ...
}
peer_t::handle_recvbuffer()
{
while (is_alive())
{
char* recv_buf = m_recvbuffer.buffer();
int recv_len = m_recvbuffer.length();
packet_t* packet = (packet_t*) recv_buf;
// 检查是否收够完整的一个包
if (recv_len < 4 /* sizeof(packet_t.len) */) break;
if (packet->len > MAX_PACKET_SIZE)
{
// 太大的包,可能是攻击包,或错误的包,不接受
stop();
break;
}
if (recv_len < 4 + packet->len) break;
// 处理一个包
process_packet(packet);
// 把已处理的包清除出缓存区
m_recvbuffer.descard(4 + packet->len);
}
}
peer_t::handle_sendbuffer()
{
while (is_alive())
{
char* buf_ptr = m_sendbuffer.buffer();
int buf_len = m_sendbuffer.length();
if (buf_len < 1) break;
// 尽量发,能发多少就多少,剩下的下次再发
int send_len = send(...buf_ptr, buf_len);
if (send_len > 0)
{
// 把已发的清除出缓存区
m_sendbuffer.descard(send_len);
} else if ....
}
}
当然如果你是发送文件,一般做法是先发一个包头,然后源源不断的发文件数据,那就是另一个做法了,因为上面的代码是最起码收完一个完整包到缓存区才分析运作,而且限制了最大包头长度。稍为改一下就可以。
#11
谢谢大家,我以解决这个问题,是接收端的问题,我的程序会处理拈包问题,所以不会在这个问题上,最后确定SOCKET的接收函数revc使用阻塞方式,要求收1024可是收了640就返回了,