所以,我尝试用C++中的套接字编程在客户端和服务器之间发送数据。现在,我在StackOverflow中读到了一个答案,其中提到我们必须检查每次发送时接收到多少原始msg,然后等待,直到我们完全获得信息。为此,我使用了以下sendMsg()和receive()函数。
string receive()
{
string msg = "";
char last_character = '%';
do
{
char buffer[2048] = {0};
read(sockfd, buffer, 2048);
string s(buffer);
msg += s;
last_character = s[s.size() - 1];
} while (last_character != '|');
return msg.substr(0, msg.size() - 1);
}
bool sendMsg(string s)
{
s += '|';
char buffer[s.size()];
strcpy(buffer, &s[0]);
int bytes_total = 0;
int bytes_left = s.length();
int bytes_now = 0;
while (bytes_left > 0)
{
bytes_now = send(sockfd, &buffer[bytes_total], bytes_left, 0);
if (bytes_now == -1)
{
err("Error sending message");
return false;
}
assert(bytes_now <= bytes_left);
bytes_left -= bytes_now;
bytes_total += bytes_now;
}
return true;
}
这在大多数情况下都很好用,只是有时会添加一个“|'字符,即消息前的分隔符。当我将一个新客户端连接到服务器,并尝试向客户端发送一些消息以在其控制台中打印时,这个问题就很突出。类似于以下内容:
usernames[username] = client_socket;
comm.sendMsg(string(GRN) + "Username accepted.\n" + string(NRM));
cout << GRN << username << " connected." << NRM << endl;
comm.sendMsg(readme(username));
其中,用户名是一个无序Map,它存储每个唯一用户名的客户端套接字,自述文件函数只是一个字符串,如“欢迎来到聊天室“,+用户名。这里,#define NRM“\x1B[0m”,#define GRN“\x1B[32m”
所以,有时我得到的输出是
Enter the IP address of the server: l
Connected to server.
Enter your username: user
Username accepted.
|
+------------------------------------------------------------+
| |
| [server]: Welcome to the chatroom, user |
| |
| [server]: Here are the commands you can use: |
| |
| 1. status : Lists the status of all users |
| 2. connect [username] : Connect to username to start |
| chatting |
| 3. goodbye : Ends current chatting session |
| 4. close : Disconnects the user from the |
| server |
| 5. clear : Clears the chat from the window |
| 6. Ctrl + C (client) : Disconnects the client and |
| terminates its chat session |
| if present |
| 7. Ctrl + C (server) : Terminates the server and all the|
| clients connected to the server |
+------------------------------------------------------------+
您可以注意到|就在Username accepted行之后,这是不必要的。我无法找出问题所在。是sendMsg和receive函数有问题吗?或者没问题,我必须查看其余代码。客户端和服务器文件接近700行C++代码,所以我没有直接在这里发布。
编辑:我修改了接收函数如下:
string receive()
{
string msg = "";
char last_character = '%';
while (last_character != '|')
{
char buffer[2048] = {0};
int bytes_read = read(sockfd, buffer, 2048);
if (bytes_read <= 0)
{
err("Error receiving message");
return "";
}
string s(buffer, bytes_read);
for (int i = 0; i < s.size() - 1; i++)
if (s[i] == '|')
{
s.erase(s.begin() + i);
}
msg += s;
last_character = s[s.size() - 1];
}
return msg.substr(0, msg.size() - 1);
}
1条答案
按热度按时间irlmq6kh1#
这将向套接字写入一个字符串,后跟一个尾随的
|
。紧接着,这将写入第二个这样的字符串。
这里这个逻辑的期望是,这将最多读取一条消息,也许是部分读取。
这种期望是有缺陷的。
不管什么原因,如果服务器直到发送方向它写入了***两条***消息之后才开始
read()
ing套接字,那么这将把两条消息都读入buffer
,并且所示的代码将完全不知道这一点。在进行任何进一步的调试之前,需要修复此逻辑错误,因为此逻辑错误会使所有后续观察变得毫无价值。
顺便说一句:上面的内容完全不需要。
s.c_str()
和s.size()
一起,提供了write()
字符串所需的一切。不需要单独的char
缓冲区。