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 */
}