【问题标题】:How do you send a programs current working directory in C using the winsock2 library?如何使用 winsock2 库在 C 中发送程序当前工作目录?
【发布时间】:2020-04-15 17:00:37
【问题描述】:

这是我的代码:

#include <stdio.h>
#include <unistd.h>
#include <windows.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")

int main(){
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serverAddr, clientAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(6969);
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    listen(serverSocket, 1);

    int s_size = sizeof(struct sockaddr_in);
    SOCKET clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &s_size);

    char cwd[1024];
    getcwd(cwd, 1024);

    printf(cwd);

    send(clientSocket, cwd, sizeof(cwd), 0);

    return 0;
}

这意味着将程序的 cwd 发送到 python 脚本,但是每当我运行 python 脚本时,它在收到 cwd 时都会给我这个错误:

cwd = clientSocket.recv(1024).decode("utf-8").strip()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd4 in position 44: invalid continuation byte

每当我在 C 程序上打印 cwd 时,它都会毫无问题地打印出来。 我试过用 null 来终止这样的字符串:

cwd[strlen(cwd)] = 0;

它没有改变任何东西。

我最好的猜测是实际路径和空终止符之间的数据是导致 python 脚本端编码错误的原因,但我无法为路径分配足够的内存,因为我不知道分配内存之前的路径,所以我选择了 1024,因为我觉得这是一个合理的值。

有人知道我该如何解决这个问题吗?

编辑: 我解决了。由于缓冲区大小 (1024) 较大,cwd 字符串与实际字符串一起包含大量垃圾。我设法为 cwd 分配内存并将其重新分配给它的 strlen()。

char *cwd = malloc(1024*sizeof(char));
getcwd(cwd, 1024);
realloc(cwd, strlen(cwd));

printf(cwd);

send(clientSocket, cwd, strlen(cwd), 0);

这对我有用。

【问题讨论】:

  • 您正在发送完整的 char 缓冲区,包括 NUL 字节之后的垃圾。试试send(clientSocket, cwd, strlen(cwd) + 1, 0);
  • 现在它给了我这个错误:ConnectionResetError: [Errno 104] Connection reset by peer
  • 连接重置是来自 python 程序(如我所料),还是来自 C 中的发送程序?
  • 你应该closeclientSocket

标签: python c sockets encoding winsock2


【解决方案1】:

我不了解 Python,但我相信我知道这里发生了什么:这似乎是两种处理字符串的不同方式之间的阻抗不匹配。这需要几个步骤。

在 C 端,它是一个字符缓冲区:

char cwd[1024];
getcwd(cwd, sizeof cwd);
send(clientSocket, cwd, sizeof(cwd), 0);

cwd 缓冲区的内容当前目录字符串将是一个 NUL 字节加上堆栈中的随机垃圾,整个缓冲区正在通过网络发送到Python 程序。

我最初的建议是只发送有效的数据:

send(clientSocket, cwd, strlen(cwd), 0);  // don't do this after all

它不发送垃圾,但现在我们发现另一个问题:接收方期望一个完整的 1024 字节:

cwd = clientSocket.recv(1024).decode("utf-8").strip()

问题是,发送方传输的字节少得多(/home/steve/myproject 的长度或其他),并且由于 TCP 套接字不遵守消息边界,它仍在尝试读取完整的 1024。

我怀疑连接重置是因为你的 C 程序在发送后退出,这会关闭套接字,而 Python 端在接收完所有内容之前观察到这个关闭。

解决这个问题的正确方法可能涉及超时和接收端的缓冲,但这看起来需要做很多工作,所以我会稍微改变一下方向。

现在我们将返回发送一个固定大小的缓冲区(如您建议的 1024),这意味着双方同意数据大小,但您必须修改 Python 端以仅提取有趣的部分字符串,忽略 NUL 字节以及它之外的内容。

在 Python 方面,您仍然会使用 cwd = clientSocket.read(1024),但随后您必须进行缓冲区操作以找出第一个 NUL 字节在哪里,并且最多只能使用(但不包括)该字符缓冲区。

生成的子集(例如 47 个字节)将是一个您应该能够解码和使用的字符串。

您的结果可能会有所不同,具体取决于 Python 允许您操作缓冲区并将其转换为字符串的方式;我不知道。

【讨论】:

  • 这听起来像是一个可能的解决方案。所以在 C 代码中,当我在字符串的末尾添加一个空终止符时,它是将它添加到内存部分的末尾还是只是有效字符的末尾?我以为它会在垃圾数据的末尾添加 0,所以最后会有实际数据、垃圾数据和 nul 终止符。
  • @dekotu - 当您添加 NUL 字节时,它会进入字符数组中的 一个位置,紧跟在您关心的字符 (/home/steve/myproject/) 之后,但一切在 NUL 字节未知并且可能是垃圾之后。
  • 它没有尝试读取完整的 1024 个字符。它将在已读取的任何内容处停止。
  • 我设法解决了。我动态分配 cwd,然后将其重新分配给它的 strlen()。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-10
相关资源
最近更新 更多