Bagaimana Anda mengirim direktori kerja program saat ini di C menggunakan perpustakaan winock2?

Ini kode saya:

#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;
}

Ini dimaksudkan untuk mengirim cwd program ke skrip python tetapi setiap kali saya menjalankan skrip python, saya mendapat kesalahan ini ketika menerima cwd:

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

Setiap kali saya mencetak cwd pada program C, ia akan mencetak tanpa masalah. Saya telah mencoba null mengakhiri string seperti ini:

cwd[strlen(cwd)] = 0;

Itu tidak mengubah apapun.

Tebakan terbaik saya adalah bahwa data antara jalur sebenarnya dan terminator nol adalah apa yang menyebabkan kesalahan pengkodean pada akhir skrip python, tetapi saya tidak dapat mengalokasikan cukup memori untuk jalur tersebut karena saya tidak dapat mengetahui panjang jalur sebelum mengalokasikan memori, jadi saya memilih 1024 karena menurut saya itu adalah nilai yang masuk akal.

Adakah yang tahu bagaimana saya bisa memperbaikinya?

EDIT: Saya menyelesaikannya. String cwd memiliki banyak sampah di dalamnya bersama dengan string sebenarnya karena ukuran buffer yang besar (1024). Saya berhasil mengalokasikan memori untuk cwd dan mengalokasikannya kembali ke strlen()-nya.

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

printf(cwd);

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

Ini berhasil untuk saya.


person Community    schedule 24.12.2019    source sumber
comment
Anda mengirimkan buffer char penuh, termasuk sampah setelah byte NUL. Coba send(clientSocket, cwd, strlen(cwd) + 1, 0);   -  person Steve Friedl    schedule 24.12.2019
comment
Sekarang ini memberi saya kesalahan ini: ConnectionResetError: [Errno 104] Connection reset by peer   -  person    schedule 24.12.2019
comment
Apakah Connection Reset berasal dari program python (seperti yang saya harapkan), atau dari program pengirim di C?   -  person Steve Friedl    schedule 24.12.2019
comment
Anda harus menutup clientSocket.   -  person Andrii    schedule 24.12.2019


Jawaban (1)


Saya tidak tahu Python tapi yakin saya melihat apa yang terjadi di sini: tampaknya ada ketidakcocokan impedansi antara dua cara berbeda dalam menangani string. Ini memerlukan beberapa langkah.

Di sisi C, ini adalah buffer karakter:

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

dan konten buffer cwd setelah string direktori saat ini akan menjadi byte NUL ditambah sampah acak dari tumpukan, dan seluruh buffer ini dikirim melalui jaringan ke program Python.

Usulan awal saya adalah mengirimkan data sebanyak yang valid saja:

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

yang tidak mengirimkan sampah, tapi sekarang kita menemukan masalah lain: pihak penerima mengharapkan 1024 byte penuh:

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

Masalahnya adalah, pengirim mengirimkan byte yang jauh lebih sedikit (panjang /home/steve/myproject atau apa pun), dan karena soket TCP tidak memenuhi batas pesan, ia masih mencoba membaca 1024 penuh.

Saya menduga Reset Koneksi terjadi karena program C Anda keluar setelah pengiriman, yang menutup soket, dan pihak Python mengamati penutupan ini sebelum selesai menerima semuanya.

Cara yang tepat untuk memperbaikinya mungkin melibatkan waktu tunggu dan buffering di sisi penerima, tetapi ini sepertinya membutuhkan banyak pekerjaan, jadi saya akan mengubah arah sedikit.

Sekarang kita akan kembali mengirimkan buffer berukuran tetap (1024 seperti yang Anda sarankan), yang berarti kedua belah pihak menyetujui ukuran data, tetapi Anda harus memodifikasi sisi Python untuk mengekstrak hanya bagian yang menarik dari string tersebut. , mengabaikan byte NUL dan apa yang ada di luarnya.

Di sisi Python, Anda masih akan melakukan cwd = clientSocket.read(1024) tetapi kemudian Anda harus melakukan manipulasi buffer untuk mengetahui di mana byte NUL pertama berada, dan hanya menggunakan hingga (tetapi tidak termasuk) karakter tersebut dalam buffer.

Subset yang dihasilkan (misalnya, 47 byte) akan menjadi string yang dapat Anda dekode dan gunakan.

Hasil Anda mungkin berbeda tergantung pada bagaimana Python memungkinkan Anda memanipulasi buffer dan mengubahnya menjadi string; Aku tidak tahu.

person Steve Friedl    schedule 24.12.2019
comment
Ini sepertinya solusi yang mungkin. Jadi dalam kode C, ketika saya menambahkan terminator nol di akhir string, apakah itu menambahkannya ke akhir bagian memori atau hanya di akhir karakter yang valid? Saya pikir itu akan menambahkan 0 di akhir data sampah, jadi saya akan memiliki data aktual, data sampah, dan terminator nol di akhir. - person ; 24.12.2019
comment
@dekotu - Saat Anda menambahkan byte NUL, byte tersebut masuk ke satu posisi di dalam larik karakter, tepat setelah karakter yang Anda minati (/home/steve/myproject/), tetapi semua yang ada setelah byte NUL tidak diketahui dan mungkin sampah. - person Steve Friedl; 24.12.2019
comment
Itu tidak mencoba membaca 1024 karakter penuh. Itu akan berhenti pada apa pun yang telah dibaca. - person user207421; 25.12.2019
comment
Saya berhasil menyelesaikannya. Saya secara dinamis mengalokasikan cwd dan kemudian mengalokasikannya kembali ke strlen()-nya. - person ; 25.12.2019