คุณจะส่งไดเร็กทอรีการทำงานปัจจุบันของโปรแกรมใน C โดยใช้ไลบรารี winsock2 ได้อย่างไร

นี่คือรหัสของฉัน:

#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

เมื่อใดก็ตามที่ฉันพิมพ์ cwd บนโปรแกรม C มันจะพิมพ์โดยไม่มีปัญหาใดๆ ฉันได้ลองยกเลิกสตริงเป็นโมฆะแล้ว:

cwd[strlen(cwd)] = 0;

มันไม่ได้เปลี่ยนแปลงอะไรเลย

การคาดเดาที่ดีที่สุดของฉันคือข้อมูลระหว่างเส้นทางจริงและจุดสิ้นสุดที่เป็นโมฆะคือสิ่งที่ทำให้เกิดข้อผิดพลาดในการเข้ารหัสที่จุดสิ้นสุดของสคริปต์หลาม แต่ฉันไม่สามารถจัดสรรหน่วยความจำเพียงพอสำหรับเส้นทางได้เนื่องจากฉันไม่สามารถทราบความยาวของเส้นทางก่อนที่จะจัดสรร หน่วยความจำ ดังนั้นฉันจึงเลือก 1024 เพราะฉันรู้สึกว่ามันเป็นค่าที่สมเหตุสมผล

ใครรู้ว่าฉันจะแก้ไขปัญหานี้ได้อย่างไร

แก้ไข: ฉันแก้ไขมันแล้ว สตริง cwd มีขยะจำนวนมากอยู่ในนั้นพร้อมกับสตริงจริง เนื่องจากมีบัฟเฟอร์ขนาดใหญ่ (1024) ฉันจัดการจัดสรรหน่วยความจำสำหรับ cwd แทนและจัดสรรใหม่ให้กับ strlen()

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

printf(cwd);

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

สิ่งนี้ได้ผลสำหรับฉัน


person Community    schedule 24.12.2019    source แหล่งที่มา
comment
คุณกำลังส่งบัฟเฟอร์ char เต็ม รวมถึงขยะที่อยู่หลังไบต์ NUL ลอง send(clientSocket, cwd, strlen(cwd) + 1, 0);   -  person Steve Friedl    schedule 24.12.2019
comment
ตอนนี้มันทำให้ฉันมีข้อผิดพลาดนี้: ConnectionResetError: [Errno 104] Connection Reset by peer   -  person    schedule 24.12.2019
comment
การรีเซ็ตการเชื่อมต่อมาจากโปรแกรมหลาม (ตามที่ฉันคาดหวัง) หรือจากโปรแกรมที่ส่งใน C หรือไม่   -  person Steve Friedl    schedule 24.12.2019
comment
คุณควรปิด clientSocket   -  person Andrii    schedule 24.12.2019


คำตอบ (1)


ฉันไม่รู้จัก Python แต่เชื่อว่าฉันเห็นสิ่งที่เกิดขึ้นที่นี่: ดูเหมือนว่าจะเป็นอิมพีแดนซ์ที่ไม่ตรงกันระหว่างวิธีจัดการสตริงสองวิธีที่แตกต่างกัน การดำเนินการนี้จะใช้เวลา 2-3 ขั้นตอน

ในด้าน 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

ซึ่งไม่ส่งขยะ แต่ตอนนี้เราพบปัญหาอื่น: ฝั่งรับคาดว่าจะเต็ม 1,024 ไบต์:

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

ปัญหาคือ ผู้ส่งส่งไบต์น้อยกว่ามาก (ความยาว /home/steve/myproject หรืออะไรก็ตาม) และเนื่องจากซ็อกเก็ต TCP ไม่ได้ใช้ขอบเขตของข้อความ จึงยังคงพยายามอ่านข้อมูล 1,024 เต็ม

ฉันสงสัยว่าการรีเซ็ตการเชื่อมต่อเป็นเพราะโปรแกรม C ของคุณออกหลังจากส่ง ซึ่งปิดซ็อกเก็ต และฝั่ง Python สังเกตการปิดนี้ก่อนที่จะรับทุกอย่างเสร็จ

วิธีที่เหมาะสมในการแก้ไขปัญหานี้อาจเกี่ยวข้องกับการหมดเวลาและการบัฟเฟอร์ในฝั่งรับ แต่ดูเหมือนว่าจะยุ่งยากมาก ดังนั้นฉันจะเปลี่ยนทิศทางเล็กน้อย

ตอนนี้เราจะกลับไปส่งบัฟเฟอร์ขนาดคงที่ (1024 ตามที่คุณแนะนำ) ซึ่งหมายความว่าทั้งสองฝ่ายเห็นด้วยกับขนาดข้อมูล แต่คุณจะต้องแก้ไขด้าน Python เพื่อแยกเฉพาะส่วนที่น่าสนใจของสตริง โดยไม่สนใจไบต์ NUL และสิ่งที่อยู่นอกเหนือจากนั้น

ในด้าน Python คุณจะยังคงทำ cwd = clientSocket.read(1024) แต่จากนั้นคุณจะต้องทำการจัดการบัฟเฟอร์เพื่อดูว่าไบต์ NUL แรกอยู่ที่ไหน และใช้อักขระนั้นในบัฟเฟอร์ได้สูงสุด (แต่ไม่รวม) เท่านั้น

เซ็ตย่อยผลลัพธ์ (เช่น 47 ไบต์) จะเป็นสตริงที่คุณควรจะสามารถถอดรหัสและใช้งานได้

ผลลัพธ์ของคุณอาจแตกต่างกันไปขึ้นอยู่กับวิธีที่ Python อนุญาตให้คุณจัดการบัฟเฟอร์และแปลงให้เป็นสตริง ฉันไม่รู้.

person Steve Friedl    schedule 24.12.2019
comment
ดูเหมือนเป็นทางออกที่เป็นไปได้ ดังนั้นในโค้ด C เมื่อฉันเพิ่มตัวยุติที่เป็นโมฆะที่ท้ายสตริง มันจะเพิ่มลงที่ส่วนท้ายของส่วนหน่วยความจำหรือเพียงส่วนท้ายของอักขระที่ถูกต้องหรือไม่ ฉันคิดว่ามันจะเพิ่ม 0 ที่ส่วนท้ายของข้อมูลขยะ ดังนั้นฉันจะมีข้อมูลจริง ข้อมูลขยะ และตัวยุติ nul ที่ส่วนท้าย - person ; 24.12.2019
comment
@dekotu - เมื่อคุณเพิ่มไบต์ NUL มันจะไปที่ ตำแหน่งเดียว ภายในอาร์เรย์อักขระ ทันทีหลังจากอักขระที่คุณสนใจ (/home/steve/myproject/) แต่ทุกอย่างที่อยู่หลังไบต์ NUL ไม่เป็นที่รู้จักและอาจเป็นขยะ - person Steve Friedl; 24.12.2019
comment
ไม่ได้พยายามอ่านอักขระเต็ม 1,024 ตัว มันจะหยุดอยู่แค่เรื่องที่อ่านมา - person user207421; 25.12.2019
comment
ฉันจัดการเพื่อแก้ไขมัน ฉันจัดสรร cwd แบบไดนามิกแล้วจัดสรรใหม่ให้กับ strlen() - person ; 25.12.2019