程序中的“行”部分需要在每次消息传输后清除,但我一直无法做到这一点。
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdbool.h>
#include <iostream>
const char* ip = "127.0.0.1";
int port = 1752;
#pragma comment (lib, "ws2_32.lib")
int main() {
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
printf("[!] Winsock failed..\n");
exit(-1);
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
printf("[!] Socket creat was fail..\n");
WSACleanup();
exit(-1);
}
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, &(address.sin_addr));
if (connect(sock, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) {
printf("[!] Connect was fail.. \n");
closesocket(sock);
WSACleanup();
exit(-1);
}
char buffer[1024];
char name[1024];
printf("Enter the username: \n");
std::cin.getline(name, sizeof(name));
size_t nameCount = strlen(name);
name[strcspn(name, "\n")] = '\0';
char line[1024];
printf("Enter the messages: \n");
while (true) {
std::cin.getline(line, sizeof(line));
size_t charCount = strlen(line);
line[charCount - 1] = '\0';
line[strcspn(line, "\n")] = '\0';
sprintf_s(buffer, sizeof(buffer), "%s: %s", name, line);
if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR) {
printf("[!] Send failed\n");
break;
}
}
WSACleanup();
closesocket(sock);
}
我希望“行”部分在每次消息传输后都被完全清除,并且不会与下一条消息混淆,但它没有被正确清除
您不会在每个
line
之后将 send()
的内容清零。这就是为什么您会看到 line
在下一个 cin.getline()
之后可能仍保留较早的数据。您可以使用 std::memset()
进行归零,例如:
while (std::cin.getline(line, sizeof(line))) {
...
std::memset(line, 0, sizeof(line));
}
另一种选择是注意实际返回给您的字符数
cin.getline()
,并且不要使用比这更多的字符。那么你就不需要浪费时间将 line
归零,或者浪费时间使用 strlen()
来计算输出长度。 cin.gcount()
返回后,输出长度由cin.getline()
报告。
除此之外,我发现您的代码还存在其他一些问题:
缺乏对
cin.getline()
和 send()
足够的错误检查。
您不确定
cin.getline()
实际上正在向您返回可用数据。
send()
可以(通常确实)返回比请求更少的字节,因此您需要循环调用它,直到所有字节实际上都被接受。
您没有向接收者发送
buffer
的长度或任何终止符,因此接收者无法知道每个 buffer
消息的实际大小。您需要:
在发送消息本身之前发送消息的长度。然后接收器可以先读取长度,然后读取长度所说的字节/字符。
在消息后发送唯一的终止符,例如
\n
或\0
。然后接收器可以读取,直到终结符到达。
在
send()
循环之后关闭应用程序期间,您在 WSACleanup()
之前调用 closesocket()
。您需要交换它们。
话虽如此,尝试更像这样的事情:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#pragma comment (lib, "ws2_32.lib")
const char* ip = "127.0.0.1";
int port = 1752;
bool sendRaw(SOCKET sock, const void *buffer, size_t bufsize) {
const char *pbuf = reinterpret_cast<const char*>(buffer);
while (buflen > 0) {
int sent = send(sock, pbuf, static_cast<int>(buflen), 0);
if (sent == SOCKET_ERROR) {
std::cerr << "[!] Send failed\n";
return false;
}
pbuf += sent;
buflen -= sent;
}
return true;
}
bool sendStr(SOCKET sock, const std::string& str) {
return sendRaw(sock, str.c_str(), str.size());
}
int main() {
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
std::cerr << "[!] Winsock startup failed..\n";
return -1;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
std::cerr << "[!] Socket create failed..\n";
WSACleanup();
return -1;
}
sockaddr_in address = {};
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, &(address.sin_addr));
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == SOCKET_ERROR) {
std::cerr << "[!] Connect failed.. \n";
closesocket(sock);
WSACleanup();
return -1;
}
std::string name;
std::cout << "Enter the username:\n";
if (std::getline(std::cin, name) && !name.empty()) {
std::string line;
std::cout << "Enter the messages:\n";
while (std::getline(std::cin, line)) {
if (!sendStr(sock, name + ": " + line + "\n")) {
break;
}
}
}
closesocket(sock);
WSACleanup();
return 0;
}