ซ็อกเก็ต TCP ในค

ฉันกำลังพยายามเขียนอินเทอร์เฟซซ็อกเก็ต TCP สำหรับโปรแกรมของฉัน และฉันกำลังดึงผมออกโดยมีข้อผิดพลาด Accept() (ฉันคิดว่า) สำหรับสิ่งนี้ ฉันได้สร้างโค้ดทดสอบแบบสรุปแล้ว
ก่อนอื่น ฉันต้องตั้งค่าเล็กน้อย

int server_socket = 0;
server_socket = socket(AF_INET, SOCK_STREAM, 0);

int accepted_connection = 0;

struct sockaddr_in server_address;
server_address.sin_port = htons(9001);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;

struct sockaddr_in client_address;
client_address.sin_port = 0;
client_address.sin_family = AF_INET;

char * server_socket_read_buffer[100] = {0};
int server_socket_read_length = 0;

ทุกสิ่งค่อนข้างเรียบง่าย เพียงจัดสรรตัวแปรบางส่วน ต่อไปฉันจะผูกมัดและฟัง

if (bind(server_socket,(struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
    perror("Bind() on server_socket has failed\n");
}

if (listen(server_socket, 10) < 0)
{
    perror("Listen() on server_socket has failed\n");
}

ต่อไปคือส่วนที่ฉันเชื่อว่าฉันมีปัญหา

printf("Attempting accept!\n");
if (accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL) < 0)
{
    perror("Accept failed\n");
}
sleep(10);
if (server_socket_read_length = read(accepted_connection, &server_socket_read_buffer, server_socket_read_length) < 0)
{
    perror("Read failed\n");
}
printf("Read %d bytes from socket\n", server_socket_read_length);
for (int i = 0; i<server_socket_read_length;i++)
{
    printf("%x\n",server_socket_read_buffer[i]);
}

สิ่งนี้จะคอมไพล์และรัน เมื่อฉันใช้ nc ด้วยคำสั่ง 'nc 127.0.0.1 9001' ฉันได้รับการเชื่อมต่อ แต่ไม่มีข้อมูลถูกอ่าน โดยเฉพาะฉันได้รับข้อมูล 0 ไบต์ ฉันคิดว่านี่อาจเป็นเพราะค่า NULL ในบรรทัดยอมรับ แต่การเปลี่ยนสิ่งเหล่านั้นเป็นโครงสร้างและความยาวที่เหมาะสมทำให้โค้ดของฉันไม่สามารถคอมไพล์ได้

หากใครสามารถให้ความกระจ่างเกี่ยวกับสิ่งที่ฉันทำผิดฉันจะขอบคุณมาก


person Darakian    schedule 06.07.2015    source แหล่งที่มา
comment
คุณอยู่บนเครื่องที่จำเป็นต้องใช้ htons() หรือไม่? นั่นคือการสลับไบต์และคุณอาจตั้งค่าพอร์ต 0x2923 (10531) แทน 0x2329 (9001) ได้เป็นอย่างดี   -  person Marc B    schedule 06.07.2015
comment
คุณควรใช้ htons() กับค่าคงที่เสมอเมื่อตั้งค่าฟิลด์ sin_port บนเครื่อง little-endian ไบต์จะถูกกลับด้าน ในขณะที่เครื่อง big-endian นั้นไม่ต้องดำเนินการ   -  person dbush    schedule 06.07.2015


คำตอบ (3)


มีข้อผิดพลาดสองสามประการ:

  1. INADDR_ANY อยู่ในลำดับไบต์ของโฮสต์ และจำเป็นต้องแปลงเป็นเครือข่ายเช่น htonl(INADDR_ANY) แต่มันไม่สำคัญเนื่องจากค่าคงที่ INADDR_ANY ถูกกำหนดเป็น 0

  2. นี้

    char * server_socket_read_buffer[100]
    

    ควรจะเป็น

    char server_socket_read_buffer[100]
    
  3. นี้

    read(accepted_connection, &server_socket_read_buffer, server_socket_read_length)
    

    ควรจะเป็น

    read(accepted_connection, server_socket_read_buffer, sizeof server_socket_read_buffer)
    
person Maxim Egorushkin    schedule 06.07.2015
comment
ฉันได้ทำการเปลี่ยนแปลงตามที่คุณแนะนำแล้ว และดูเหมือนว่าโปรแกรมกำลังบล็อกบรรทัดการอ่านอยู่ ฉันส่งข้อมูลไปมากกว่า 100 ไบต์แล้ว ฉันไม่พบสิ่งใดในหน้า man ที่ read() เกี่ยวกับว่าเป็นฟังก์ชันบล็อก คิด? - person Darakian; 06.07.2015
comment
@Darakian ทำไม sleep ถึงอยู่ในนั้น? - person David Schwartz; 06.07.2015
comment
@DavidSchwartz มันไม่ใช่อีกต่อไป การนอนหลับอยู่ที่นั่นเพื่อให้แน่ใจว่าฉันมีเวลามากพอที่จะทุบคีย์บอร์ดของฉันในเทอร์มินัลอื่นเพื่อส่งข้อมูล - person Darakian; 06.07.2015
comment
@Darakian Test อยู่กับ echo abc | nc 127.0.0.1 9001 และโพสต์รหัสที่สมบูรณ์หากไม่ได้ผล - person Maxim Egorushkin; 07.07.2015

คุณกำลังส่งผ่าน server_socket_read_length = 0 ซึ่งทำให้ความยาวการอ่านสูงสุดเป็นศูนย์ ผ่านขนาดบัฟเฟอร์ การประกาศ server_socket_read_buffer ก็ไม่ถูกต้องเช่นกัน อาจเป็นไปได้ว่าคุณควรจัดสรรบัฟเฟอร์ที่ใหญ่กว่า (เช่น 4KB) บนฮีป

ถอดการนอนหลับออกด้วย

ส่วนที่เหลืออาจใช้งานได้เนื่องจาก nc ได้รับการเชื่อมต่อ และคุณสามารถยอมรับและอ่านได้โดยไม่มีข้อผิดพลาด

person usr    schedule 06.07.2015
comment
แล้วฉันก็รู้สึกโง่ ขอบคุณที่ชี้ให้เห็นความยาวเป็นศูนย์ให้ฉัน ปัญหายังไม่ได้รับการแก้ไขอย่างสมบูรณ์ แต่สิ่งนี้ช่วยได้ - person Darakian; 06.07.2015

หลังจากต่อสู้ดิ้นรนมากขึ้น ฉันก็พบคำตอบสุดท้าย บล็อก

    if (accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL) < 0)
    {
    //code
    }

ใช้งานไม่ได้ การอ่านของฉันในภายหลังถูกบล็อกเนื่องจาก Accept_connection ไม่ใช่ซ็อกเก็ตที่ถูกต้อง เปลี่ยนเป็น

    (accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL);
    if accepted_connection < 0)
    {
    //code
    }

แก้ไขปัญหาของฉันแล้ว เท่าที่ฉันสามารถรวบรวม file descriptor ไม่ได้ถูกสร้างขึ้นในแนวเดียวกับ if() และการอ่านข้อมูลจากจำนวนเต็มไม่ได้มีประโยชน์มาก
ขอบคุณสำหรับข้อมูลของทุกคน

person Darakian    schedule 06.07.2015