Unix Socket - ฟังก์ชั่นหลัก

บทนี้อธิบายถึงฟังก์ชันซ็อกเก็ตหลักที่จำเป็นในการเขียนไคลเอ็นต์และเซิร์ฟเวอร์ TCP ที่สมบูรณ์

แผนภาพต่อไปนี้แสดงการโต้ตอบกับไคลเอนต์และเซิร์ฟเวอร์ที่สมบูรณ์ -

ฟังก์ชั่นซ็อกเก็ต

ในการดำเนินการ I / O เครือข่ายสิ่งแรกที่กระบวนการต้องทำคือเรียกใช้ฟังก์ชันซ็อกเก็ตระบุประเภทของโปรโตคอลการสื่อสารที่ต้องการและตระกูลโปรโตคอลเป็นต้น

#include <sys/types.h>
#include <sys/socket.h>

int socket (int family, int type, int protocol);

การโทรนี้ส่งคืนตัวอธิบายซ็อกเก็ตที่คุณสามารถใช้ในการเรียกระบบในภายหลังหรือ -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

family - ระบุตระกูลโปรโตคอลและเป็นหนึ่งในค่าคงที่ที่แสดงด้านล่าง -

ครอบครัว คำอธิบาย
AF_INET โปรโตคอล IPv4
AF_INET6 โปรโตคอล IPv6
AF_LOCAL โปรโตคอลโดเมน Unix
AF_ROUTE การกำหนดเส้นทางซ็อกเก็ต
AF_KEY เต้ารับ

บทนี้ไม่ครอบคลุมโปรโตคอลอื่น ๆ ยกเว้น IPv4

type- ระบุประเภทของซ็อกเก็ตที่คุณต้องการ สามารถใช้ค่าใดค่าหนึ่งต่อไปนี้ -

ประเภท คำอธิบาย
SOCK_STREAM ซ็อกเก็ตสตรีม
SOCK_DGRAM ซ็อกเก็ต Datagram
SOCK_SEQPACKET ซ็อกเก็ตแพ็คเก็ตตามลำดับ
SOCK_RAW ซ็อกเก็ตดิบ

protocol - ควรตั้งค่าอาร์กิวเมนต์เป็นประเภทโปรโตคอลเฉพาะที่ระบุด้านล่างหรือ 0 เพื่อเลือกค่าเริ่มต้นของระบบสำหรับการรวมตระกูลและประเภทที่กำหนด -

มาตรการ คำอธิบาย
IPPROTO_TCP โปรโตคอลการขนส่ง TCP
IPPROTO_UDP โปรโตคอลการขนส่ง UDP
IPPROTO_SCTP โปรโตคอลการขนส่ง SCTP

เชื่อมต่อฟังก์ชั่น

เชื่อมต่อฟังก์ชั่นการใช้งานโดยลูกค้า TCP ที่จะสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ TCP

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

การเรียกนี้จะคืนค่า 0 หากเชื่อมต่อกับเซิร์ฟเวอร์สำเร็จมิฉะนั้นจะส่งกลับค่า -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • serv_addr - เป็นตัวชี้ไปยัง struct sockaddr ที่มีที่อยู่ IP ปลายทางและพอร์ต

  • addrlen - ตั้งค่าเป็น sizeof (struct sockaddr)

ผูกฟังก์ชั่น

ผูกฟังก์ชั่นกำหนดอยู่โปรโตคอลท้องถิ่นเพื่อซ็อกเก็ต ด้วยอินเทอร์เน็ตโปรโตคอลที่อยู่โปรโตคอลคือการรวมกันของที่อยู่ IPv4 32 บิตหรือที่อยู่ IPv6 แบบ 128 บิตพร้อมกับหมายเลขพอร์ต TCP หรือ UDP 16 บิต ฟังก์ชันนี้เรียกโดยเซิร์ฟเวอร์ TCP เท่านั้น

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *my_addr,int addrlen);

การเรียกนี้จะคืนค่า 0 หากผูกกับแอดเดรสสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • my_addr - เป็นตัวชี้ไปยัง struct sockaddr ที่มีที่อยู่ IP และพอร์ตในเครื่อง

  • addrlen - ตั้งค่าเป็น sizeof (struct sockaddr)

คุณสามารถใส่ที่อยู่ IP และพอร์ตของคุณโดยอัตโนมัติ

ค่า 0 สำหรับหมายเลขพอร์ตหมายความว่าระบบจะเลือกพอร์ตแบบสุ่มและค่าINADDR_ANYสำหรับที่อยู่ IP หมายความว่าที่อยู่ IP ของเซิร์ฟเวอร์จะถูกกำหนดโดยอัตโนมัติ

server.sin_port = 0;  		     
server.sin_addr.s_addr = INADDR_ANY;

NOTE- สงวนพอร์ตทั้งหมดที่ต่ำกว่า 1024 คุณสามารถตั้งค่าพอร์ตที่สูงกว่า 1024 และต่ำกว่า 65535 ได้เว้นแต่จะเป็นพอร์ตที่ใช้งานโดยโปรแกรมอื่น

ฟังก์ชั่น

ฟังก์ชั่นที่เรียกว่าโดยเซิร์ฟเวอร์ TCP เท่านั้นและจะดำเนินการสองการกระทำ -

  • ฟังก์ชั่นฟังจะแปลงซ็อกเก็ตที่ไม่ได้เชื่อมต่อเป็นซ็อกเก็ตแบบพาสซีฟซึ่งบ่งชี้ว่าเคอร์เนลควรยอมรับการร้องขอการเชื่อมต่อขาเข้าที่ส่งไปยังซ็อกเก็ตนี้

  • อาร์กิวเมนต์ที่สองของฟังก์ชันนี้ระบุจำนวนการเชื่อมต่อสูงสุดที่เคอร์เนลควรจัดคิวสำหรับซ็อกเก็ตนี้

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);

การโทรนี้ส่งคืน 0 เมื่อสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • backlog - เป็นจำนวนการเชื่อมต่อที่อนุญาต

ยอมรับฟังก์ชั่น

ยอมรับฟังก์ชั่นที่เรียกว่าโดยเซิร์ฟเวอร์ TCP ที่จะกลับการเชื่อมต่อเสร็จสมบูรณ์ต่อไปจากด้านหน้าของคิวการเชื่อมต่อเสร็จสมบูรณ์ที่ ลายเซ็นของการโทรมีดังนี้ -

#include <sys/types.h>
#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

การเรียกนี้ส่งคืนตัวอธิบายที่ไม่ใช่เชิงลบเกี่ยวกับความสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด ตัวบอกที่ส่งคืนจะถือว่าเป็นตัวบอกเกี่ยวกับซ็อกเก็ตไคลเอ็นต์และการดำเนินการอ่านเขียนทั้งหมดจะทำบนตัวอธิบายนี้เพื่อสื่อสารกับไคลเอนต์

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • cliaddr - เป็นตัวชี้ไปยัง struct sockaddr ที่มีที่อยู่ IP และพอร์ตของไคลเอ็นต์

  • addrlen - ตั้งค่าเป็น sizeof (struct sockaddr)

ส่งฟังก์ชั่น

ส่งฟังก์ชั่นที่ใช้ในการส่งข้อมูลผ่านซ็อกเก็ตสตรีมหรือซ็อกเก็ตเดตาแกรมที่เกี่ยวโยงกัน หากคุณต้องการส่งข้อมูลผ่านซ็อกเก็ตดาตาแกรม UNCONNECTED คุณต้องใช้ฟังก์ชัน sendto ()

คุณสามารถใช้การเรียกระบบwrite ()เพื่อส่งข้อมูล ลายเซ็นมีดังนี้ -

int send(int sockfd, const void *msg, int len, int flags);

การโทรนี้ส่งคืนจำนวนไบต์ที่ส่งออกไปมิฉะนั้นจะส่งกลับ -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • msg - เป็นตัวชี้ไปยังข้อมูลที่คุณต้องการส่ง

  • len - เป็นความยาวของข้อมูลที่คุณต้องการส่ง (เป็นไบต์)

  • flags - ตั้งค่าเป็น 0

recvฟังก์ชั่น

recvฟังก์ชั่นที่ใช้ในการรับข้อมูลผ่านซ็อกเก็ตสตรีมหรือซ็อกเก็ตเดตาแกรมที่เกี่ยวโยงกัน หากคุณต้องการรับข้อมูลผ่านซ็อกเก็ตดาตาแกรมที่ไม่ได้เชื่อมต่อคุณต้องใช้ recvfrom ()

คุณสามารถใช้การเรียกระบบread ()เพื่ออ่านข้อมูล คำเรียกนี้อธิบายไว้ในบทฟังก์ชันตัวช่วย

int recv(int sockfd, void *buf, int len, unsigned int flags);

การเรียกนี้จะคืนค่าจำนวนไบต์ที่อ่านลงในบัฟเฟอร์มิฉะนั้นจะส่งกลับ -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • buf - เป็นบัฟเฟอร์ในการอ่านข้อมูล

  • len - เป็นความยาวสูงสุดของบัฟเฟอร์

  • flags - ตั้งค่าเป็น 0

sendtoฟังก์ชั่น

sendtoฟังก์ชั่นที่ใช้ในการส่งข้อมูลผ่านซ็อกเก็ตเดตาแกรมไม่เกี่ยวเนื่องกัน ลายเซ็นมีดังนี้ -

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

การโทรนี้ส่งคืนจำนวนไบต์ที่ส่งมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • msg - เป็นตัวชี้ไปยังข้อมูลที่คุณต้องการส่ง

  • len - เป็นความยาวของข้อมูลที่คุณต้องการส่ง (เป็นไบต์)

  • flags - ตั้งค่าเป็น 0

  • to - เป็นตัวชี้ไปยัง struct sockaddr สำหรับโฮสต์ที่จะต้องส่งข้อมูล

  • tolen - ตั้งค่าเป็น sizeof (Struct sockaddr)

recvfromฟังก์ชั่น

recvfromฟังก์ชั่นที่ใช้ในการรับข้อมูลจากดาต้าซ็อกเก็ตไม่เกี่ยวเนื่องกัน

int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);

การเรียกนี้จะส่งคืนจำนวนไบต์ที่อ่านลงในบัฟเฟอร์มิฉะนั้นจะส่งกลับค่า -1 เมื่อเกิดข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • buf - เป็นบัฟเฟอร์ในการอ่านข้อมูล

  • len - เป็นความยาวสูงสุดของบัฟเฟอร์

  • flags - ตั้งค่าเป็น 0

  • from - เป็นตัวชี้ไปยัง struct sockaddr สำหรับโฮสต์ที่ต้องอ่านข้อมูล

  • fromlen - ตั้งค่าเป็น sizeof (Struct sockaddr)

ใกล้ฟังก์ชั่น

ใกล้ฟังก์ชั่นที่ใช้ในการปิดการสื่อสารระหว่างลูกค้าและเซิร์ฟเวอร์ ไวยากรณ์มีดังนี้ -

int close( int sockfd );

การโทรนี้ส่งคืน 0 เมื่อสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

ปิดฟังก์ชั่น

ปิดฟังก์ชั่นที่ใช้ในการสื่อสารได้อย่างสง่างามอย่างใกล้ชิดระหว่างลูกค้าและเซิร์ฟเวอร์ ฟังก์ชันนี้ให้การควบคุมมากกว่าเมื่อเทียบกับฟังก์ชันปิด ด้านล่างนี้คือไวยากรณ์ของการปิดระบบ -

int shutdown(int sockfd, int how);

การโทรนี้ส่งคืน 0 เมื่อสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด

พารามิเตอร์

  • sockfd - เป็นตัวบอกซ็อกเก็ตที่ส่งคืนโดยฟังก์ชันซ็อกเก็ต

  • how - ใส่หนึ่งในตัวเลข -

    • 0 - ระบุว่าไม่อนุญาตให้รับ

    • 1 - ระบุว่าไม่อนุญาตให้ส่งและ

    • 2- ระบุว่าไม่อนุญาตให้ส่งทั้งสองและรับ เมื่อวิธีการที่ถูกตั้งไว้ที่ 2 มันเป็นสิ่งเดียวกับปิด ()

เลือกฟังก์ชั่น

เลือกฟังก์ชั่นแสดงให้เห็นซึ่งอธิบายไฟล์ที่ระบุมีความพร้อมสำหรับการอ่านพร้อมสำหรับการเขียนหรือมีเงื่อนไขข้อผิดพลาดที่รอดำเนินการ

เมื่อแอปพลิเคชันเรียกrecv หรือ recvfromแอปพลิเคชันจะถูกบล็อกจนกว่าข้อมูลจะมาถึงสำหรับซ็อกเก็ตนั้น แอปพลิเคชันอาจทำการประมวลผลที่มีประโยชน์อื่น ๆ ในขณะที่สตรีมข้อมูลขาเข้าว่างเปล่า อีกสถานการณ์หนึ่งคือเมื่อแอปพลิเคชันรับข้อมูลจากหลายซ็อกเก็ต

การเรียกrecv หรือ recvfromบนซ็อกเก็ตที่ไม่มีข้อมูลในคิวอินพุตจะป้องกันการรับข้อมูลจากซ็อกเก็ตอื่นในทันที การเรียกใช้ฟังก์ชันที่เลือกช่วยแก้ปัญหานี้โดยให้โปรแกรมสำรวจที่จับซ็อกเก็ตทั้งหมดเพื่อดูว่าพร้อมใช้งานสำหรับการอ่านและเขียนแบบไม่ปิดกั้นหรือไม่

ให้ด้านล่างเป็นไวยากรณ์ของการเลือก -

int select(int  nfds, fd_set  *readfds, fd_set  *writefds, fd_set *errorfds, struct timeval *timeout);

การโทรนี้ส่งคืน 0 เมื่อสำเร็จมิฉะนั้นจะส่งกลับ -1 เมื่อมีข้อผิดพลาด

พารามิเตอร์

  • nfds- ระบุช่วงของตัวอธิบายไฟล์ที่จะทดสอบ ฟังก์ชัน select () จะทดสอบตัวอธิบายไฟล์ในช่วง 0 ถึง nfds-1

  • readfds- ชี้ไปที่อ็อบเจ็กต์ประเภทfd_setที่อินพุตระบุตัวอธิบายไฟล์ที่จะตรวจสอบว่าพร้อมที่จะอ่านและเอาต์พุตระบุว่าตัวอธิบายไฟล์ใดพร้อมที่จะอ่าน สามารถเป็น NULL เพื่อระบุชุดว่าง

  • writefds- ชี้ไปที่อ็อบเจ็กต์ประเภทfd_setที่อินพุตระบุตัวอธิบายไฟล์ที่จะตรวจสอบว่าพร้อมที่จะเขียนและเอาต์พุตระบุว่าไฟล์ descriptors ใดที่พร้อมที่จะเขียน สามารถเป็น NULL เพื่อระบุชุดว่าง

  • exceptfds- ชี้ไปที่อ็อบเจ็กต์ประเภทfd_setที่อินพุตระบุตัวอธิบายไฟล์ที่จะตรวจสอบเงื่อนไขข้อผิดพลาดที่รอดำเนินการและเอาต์พุตระบุว่าตัวอธิบายไฟล์ใดมีเงื่อนไขข้อผิดพลาดที่รอดำเนินการ สามารถเป็น NULL เพื่อระบุชุดว่าง

  • timeout- ชี้ไปที่โครงสร้างเวลาที่ระบุระยะเวลาที่การเรียกเลือกควรสำรวจตัวอธิบายสำหรับการดำเนินการ I / O ที่มีอยู่ หากค่าการหมดเวลาเป็น 0 การเลือกจะส่งกลับทันที หากอาร์กิวเมนต์การหมดเวลาเป็น NULL การเลือกจะบล็อกจนกว่าที่จับไฟล์ / ซ็อกเก็ตอย่างน้อยหนึ่งไฟล์พร้อมสำหรับการดำเนินการ I / O ที่พร้อมใช้งาน มิฉะนั้นการเลือกจะกลับมาหลังจากระยะเวลาในการหมดเวลาหมดไปหรือเมื่อตัวอธิบายไฟล์ / ซ็อกเก็ตอย่างน้อยหนึ่งไฟล์พร้อมสำหรับการดำเนินการ I / O

ค่าที่ส่งคืนจาก select คือจำนวนแฮนเดิลที่ระบุในชุดตัวอธิบายไฟล์ที่พร้อมสำหรับ I / O หากถึงขีด จำกัด เวลาที่ระบุโดยฟิลด์การหมดเวลาให้เลือก return 0 มีมาโครต่อไปนี้สำหรับจัดการชุดตัวอธิบายไฟล์ -

  • FD_CLR(fd, &fdset)- ล้างบิตสำหรับ file descriptor fd ใน file descriptor set fdset

  • FD_ISSET(fd, &fdset)- ส่งคืนค่าที่ไม่ใช่ศูนย์ถ้าบิตสำหรับ file descriptor fdถูกตั้งค่าใน file descriptor set ที่ชี้โดยfdsetและเป็น 0

  • FD_SET(fd, &fdset) - ตั้งค่าบิตสำหรับ file descriptor fd ใน file descriptor set fdset

  • FD_ZERO(&fdset) - กำหนดค่าเริ่มต้น file descriptor set fdset ให้มีศูนย์บิตสำหรับตัวอธิบายไฟล์ทั้งหมด

ลักษณะการทำงานของมาโครเหล่านี้ไม่ได้กำหนดไว้หากอาร์กิวเมนต์ fd น้อยกว่า 0 หรือมากกว่าหรือเท่ากับ FD_SETSIZE

ตัวอย่าง

fd_set fds;

struct timeval tv;

/* do socket initialization etc.
tv.tv_sec = 1;
tv.tv_usec = 500000;

/* tv now represents 1.5 seconds */
FD_ZERO(&fds);

/* adds sock to the file descriptor set */
FD_SET(sock, &fds); 

/* wait 1.5 seconds for any data to be read from any single socket */
select(sock+1, &fds, NULL, NULL, &tv);

if (FD_ISSET(sock, &fds)) {
   recvfrom(s, buffer, buffer_len, 0, &sa, &sa_len);
   /* do something */
}
else {
   /* do something else */
}