如何在 c++ 中通过套接字编写多行

How to write multiple lines over a socket in c++

本文关键字:套接字 c++      更新时间:2023-10-16

套接字编程的新手,只是一个简短的问题,我正在尝试从服务器在我的客户端上显示多行输出,但我似乎无法让这些行分开。任何帮助表示赞赏。

服务器:

void help(int sock)
{
n = write(sock,"Commands:n",11);
n = write(sock,"HELP -> Displays usable commandsn",34);
n = write(sock,"BROADCAST 'message' -> Sends 'message' to every usern",54);
n = write(sock,"SEND 'user' 'message' -> Sends 'message' to 'user'n",52);
n = write(sock,"DISPLAY -> Displays all current usersn",39);
n = write(sock,"LEAVE -> Ends the current sessionn",35);
}

客户:

while(buffer[0] != 'L')
{
bzero(buffer,256);
n = read(sockfd,buffer,255);
cout << buffer << "n";
}

您的代码存在三个问题:

  1. write()的调用包括字符串的 null 终止符。 在这种情况下,你不应该那样。

  2. 您的read()代码忽略了read()的返回值。仅仅因为您要求 255 字节并不能保证您将收到 255 字节。 返回值告诉您实际接收了多少字节。 而且你收到的字节也不能保证以空结尾,所以你不能将缓冲区单独作为普通char*指针写入std::cout,这将使它寻找一个空终止符。std::cout有一个write()方法,可用于指定要写入的char数。 为此,请使用read()的返回值。

  3. 除此之外,您假设对read()的调用将读取单个完整行,以便您可以检查最后一个收到的缓冲区中的第一个char,以了解最后一行LEAVEL。 这根本不是真的,你不能依赖它。 TCP 是一个字节流,read()将接收和返回任意数量的数据,具体取决于套接字接收缓冲区中的可用数据。 如果需要读取基于行的数据,则必须将输入字节累积到某种不断增长的缓冲区中,然后在新数据到达时扫描该缓冲区以查找换行符。 然后,您可以从该缓冲区中仅删除已完成的行,并根据需要处理其内容。

尝试更多类似的东西:

int writestr(int sock, const char *str)
{
int n, len = strlen(str);
while (len > 0)
{
n = write(sock, str, len);
if (n < 0) return n;
str += n;
len -= n;
}
return 0;
}
void help(int sock)
{
n = writestr(sock, "Commands:n");
n = writestr(sock, "HELP -> Displays usable commandsn");
n = writestr(sock, "BROADCAST 'message' -> Sends 'message' to every usern");
n = writestr(sock, "SEND 'user' 'message' -> Sends 'message' to 'user'n");
n = writestr(sock, "DISPLAY -> Displays all current usersn");
n = writestr(sock, "LEAVE -> Ends the current sessionn");
}

char buffer[256];
std::string data;
std::string::size_type pos, last_pos = 0;
while (true)
{
n = read(sockfd, buffer, sizeof(buffer));
if (n <= 0) break;
std::cout.write(buffer, n);
data.append(buffer, n);
pos = data.find('n', last_pos);
if (pos != std::string::npos)
{
std::string line = data.substr(0, pos);
/* if you want to support CRLF line breaks, do this instead:
std::string::size_type len = pos;
if ((len > 0) && (data[len-1] == 'r'))
--len;
std::string line = data.substr(0, len);
*/
data.erase(0, pos+1);
if (line.compare(0, 5, "LEAVE") == 0)
break;
last_pos = 0;
}
else
last_pos = data.size();
}