我正在开发一个TCP连接程序,它由服务器和多个客户端组成。
服务器端
write(sockFd,message,strlen(message));
write(sockFd,message2,strlen(message2));
客户端
char msg[256];
bzero(msg, 256);
n = read (listenFd, msg, 255);
cout << "Msg1 " << msg << endl;
bzero(msg, 256);
n = read (listenFd, msg, 255);
cout << "Msg2 " << msg << endl;
问题是在服务器write()两个消息之后,客户端上的第一个read()可能会读取来自服务器的所有消息。 例如,输出是Msg 1 msg1content-of-msg2的内容。为什么会这样?
答案 0 :(得分:1)
TCP是一种流媒体协议,因此数据以流形式出现,这意味着每次读取都会读取缓冲区中的数据(或者您请求的数据)。
因此,如果您想将数据分解为数据包或数据报,则需要使用自己的基于会话的协议。这样做的一种方法是为传出数据添加4个字节的长度。通过这种方式,读者可以首先读取长度,并知道数据报的其余部分有多大。
答案 1 :(得分:1)
这是因为套接字写入和读取的流特性。您必须实现自己的消息区分技术。
有些变体是:
使用C ++ 11,今天是2015年,不要做旧的C风格。
例如(为简单起见,省略了错误检查):
服务器端:
// choose this type once and never change it after first release!
using message_size_t = uint64_t;
void write_message(int sockfd, const std::string & message)
{
message_size_t message_size{ static_cast<message_size_t>(message.size()) };
// check error here:
write(sockfd, &message_size, sizeof(message_size));
// and here:
write(sockfd, message.data(), message_size);
}
// use:
write_message(sockFd, message);
write_message(sockFd, message2);
客户方:
void read_bytes_internal(int sockfd, void * where, size_t size)
{
auto remaining = size;
while (remaining > 0) {
// check error here
auto just_read = recv(sockfd, where, remaining);
remaining -= just_read;
}
}
std::string read_message(int sockfd)
{
message_size_t message_size{ 0 };
read_bytes_internal(sockfd, &message_size, sizeof(message_size));
std::string result{ message_size, 0 };
read_bytes_internal(sockfd, &result[0], message_size);
return result;
}
// use:
cout << "Msg1 " << read_message(listenFd) << endl;
cout << "Msg2 " << read_message(listenFd) << endl;
(代码可能包含一些小错误,我在stackoverflow应答窗口中写了它,并且没有在IDE中进行语法检查。)