1. Struct address
1.1. Struct sockaddr{}
1 2 3 4 5 | <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token punctuation">{</span> <span class="token keyword">unsigned</span> <span class="token keyword">short</span> sa_family<span class="token punctuation">;</span> <span class="token comment">// address family, AF_xxx</span> <span class="token keyword">char</span> sa_data<span class="token punctuation">[</span><span class="token number">14</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 14 bytes of protocol address</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Cấu trúc này sử dụng hầu hết trong các system call ở phần 2, trong đó:
- sa_family là address family, có dạng AF_xxxx, chủ yếu ta sử dụng AF_INET
- sa_data[]: lưu trữ địa chỉ đích và cổng
1.2. Struct sockaddr_in{}
1 2 3 4 5 6 7 | <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> <span class="token punctuation">{</span> <span class="token keyword">short</span> <span class="token keyword">int</span> sin_family<span class="token punctuation">;</span> <span class="token comment">// Address family</span> <span class="token keyword">unsigned</span> <span class="token keyword">short</span> <span class="token keyword">int</span> sin_port<span class="token punctuation">;</span> <span class="token comment">// Port number</span> <span class="token keyword">struct</span> <span class="token class-name">in_addr</span> sin_addr<span class="token punctuation">;</span> <span class="token comment">// Internet address</span> <span class="token keyword">unsigned</span> <span class="token keyword">char</span> sin_zero<span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Same size as struct sockaddr</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
1 2 3 4 5 | <span class="token comment">// Internet address (a structure for historical reasons)</span> <span class="token keyword">struct</span> <span class="token class-name">in_addr</span> <span class="token punctuation">{</span> <span class="token keyword">unsigned</span> <span class="token keyword">long</span> s_addr<span class="token punctuation">;</span> <span class="token comment">// that's a 32-bit long, or 4 bytes</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Là một cấu trúc song song với struct sockaddr{}, bởi vì việc lưu và lấy dữ liệu trong struct sockaddr{} khá phức tạp, ta sử dụng cấu trúc này.
Đối với 1 số func yêu cầu cấu trúc trên, có thể sử dụng cấu trúc sockaddr_in sau đó tiến hành ép kiểu.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">int</span> sockfd<span class="token punctuation">;</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> my_addr<span class="token punctuation">;</span> sockfd <span class="token operator">=</span> <span class="token function">socket</span><span class="token punctuation">(</span>PF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// do some error checking!</span> my_addr<span class="token punctuation">.</span>sin_family <span class="token operator">=</span> AF_INET<span class="token punctuation">;</span> <span class="token comment">// host byte order</span> my_addr<span class="token punctuation">.</span>sin_port <span class="token operator">=</span> <span class="token function">htons</span><span class="token punctuation">(</span>MYPORT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// short, network byte order</span> my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">.</span>s_addr <span class="token operator">=</span> <span class="token function">inet_addr</span><span class="token punctuation">(</span><span class="token string">"10.12.110.57"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_zero<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'�'</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// zero the rest of the struct</span> <span class="token comment">// int bind(int sockfd, struct sockaddr *my_addr, int addrlen); </span> <span class="token function">bind</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>my_addr<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
1.3. Struct hostent{}
Cấu trúc lưu trữ dữ liệu host, chủ yếu sử dụng trong việc chuyển đổi giữa ip address và host (DNS), sử dụng ở phần 4 – Chuyển đổi giữa Host name và IP address. Đặc trưng là 2 function sau:
struct hostent* gethostbyname(const char* hostname)
struct hostent* gethostbyaddr(const char* addr, size_t len, int family)
1 2 3 4 5 6 7 8 | <span class="token keyword">struct</span> <span class="token class-name">hostent</span> <span class="token punctuation">{</span> <span class="token keyword">char</span> <span class="token operator">*</span>h_name<span class="token punctuation">;</span> <span class="token comment">/* official name of host */</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token operator">*</span>h_aliases<span class="token punctuation">;</span> <span class="token comment">/* alias list */</span> <span class="token keyword">int</span> h_addrtype<span class="token punctuation">;</span> <span class="token comment">/* host address type */</span> <span class="token keyword">int</span> h_length<span class="token punctuation">;</span> <span class="token comment">/* length of address */</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token operator">*</span>h_addr_list<span class="token punctuation">;</span> <span class="token comment">/* list of addresses */</span> <span class="token punctuation">}</span> |
2. Xử lý dữ liệu
2.1. Chuyển đổi giữa host byte và network byte
Dữ liệu được lưu trữ theo 2 kiểu Big-endian và Little-endian.
Trong lập trình socket, có 2 tên gọi lưu trữ dữ liệu là Host byte order và Network byte order(IP), tương ứng với Little-endian và Big-endian. Sử dụng Network byte order đối với các dữ liệu cần truyền qua các máy chủ khác nhau. Vì vậy cần chuyển giữa 2 kiểu dữ liệu này bằng các function sau:
- htons() — “Host to Network Short”
- htonl() — “Host to Network Long”
- ntohs() — “Network to Host Short”
- ntohl() — “Network to Host Long”
Trong đó Short thực hiện chuyển đổi với loại 2 bytes (sử dụng chuyển đổi cho port), Long là 4 bytes (sử dụng chuyển đổi cho network)
Ví dụ mình có port 64, cần lưu trữ trong biến sin_port trong struct sockaddr_sin
, và đương nhiên cần được lưu ở dạng Network byte order vì dữ liệu này được truyền đi.
64 có giá trị hex là 0x40, hay ở dạng 2 bytes được viết là 0x0040. Thực hiện chuyển đổi sin_addr = htons(64), hàm này thực hiện chuyển từ little qua big, vậy giá trị hex của nó sẽ là 0x4000 và có giá trị là 16384. Đó là lý do khi mình run chương trình sau sẽ được kết quả là 16384. Hiểu đơn giản hơn cả 2 kiểu chuyển đổi đều làm đảo byte, tuy nhiên ta có 2 loại func khác nhau để hiểu rõ loại chuyển đổi.
2.2. Chuyển đổi string host thành host address và ngược lại
inet_addr()
1 2 3 4 5 6 7 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><netinet/in.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><arpa/inet.h></span></span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> my_addr my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">.</span>s_addr <span class="token operator">=</span> <span class="token function">inet_addr</span><span class="token punctuation">(</span><span class="token string">"192.168.1.1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token number">192.168</span><span class="token number">.1</span><span class="token number">.1</span> <span class="token punctuation">(</span>Network byte order <span class="token operator">-</span> Big endian<span class="token punctuation">)</span> |
inet_aton()
1 2 3 4 5 6 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><netinet/in.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><arpa/inet.h></span></span> <span class="token keyword">int</span> <span class="token function">inet_aton</span><span class="token punctuation">(</span><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>cp<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">in_addr</span> <span class="token operator">*</span>inp<span class="token punctuation">)</span><span class="token punctuation">;</span> |
Hàm này chuyển đổi const char *cp
(string address) thành dạng numbers-and-dots, lưu trữ trong struct in_addr
mà ta sử dụng trong struct sockaddr_in
Example:
1 2 3 4 5 6 7 | <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> my_addr<span class="token punctuation">;</span> my_addr<span class="token punctuation">.</span>sin_family <span class="token operator">=</span> AF_INET<span class="token punctuation">;</span> <span class="token comment">// host byte order</span> my_addr<span class="token punctuation">.</span>sin_port <span class="token operator">=</span> <span class="token function">htons</span><span class="token punctuation">(</span>MYPORT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// short, network byte order</span> <span class="token function">inet_aton</span><span class="token punctuation">(</span><span class="token string">"10.12.110.57"</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_zero<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'�'</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// zero the rest of the struct </span> |
inet_ntoa
Chuyển đổi từ dạng numbers_and_dots thành string address
1 2 | <span class="token keyword">char</span><span class="token operator">*</span> <span class="token function">inet_ntoa</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">in_addr</span> inp<span class="token punctuation">)</span><span class="token punctuation">;</span> |
Example
1 2 | string <span class="token operator">*</span>addr <span class="token operator">=</span> <span class="token function">inet_ntoa</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">)</span><span class="token punctuation">;</span> |
3. System calls
Nguồn tham khảo: https://www.gta.ufrj.br/ensino/eel878/sockets/syscalls.html
3.1. Socket()
1 2 3 4 5 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span> <span class="token comment">//để sử dụng socket()</span></span> <span class="token keyword">int</span> <span class="token function">socket</span><span class="token punctuation">(</span><span class="token keyword">int</span> domain<span class="token punctuation">,</span> <span class="token keyword">int</span> type<span class="token punctuation">,</span> <span class="token keyword">int</span> protocol<span class="token punctuation">)</span><span class="token punctuation">;</span> |
Tạo 1 socket, trả về file descriptor, có giá trị nhỏ nhất mà chưa được sử dụng. Bằng -1 nếu thất bại.
- domain: sử dụng PF_INET
- type: SOCK_STREAM hoặc SOCK_DGRAM
- protocol: 0 để tự động chọn giao thức thích hợp
Xem thêm bằng: man socket
3.2. Bind()
Khi 1 socket được tạo, chưa có 1 giá trị nào được gán cho socket (ipaddress, port), bind() sử dụng để làm điều đó. Xem thêm tại man bind
1 2 3 4 5 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token keyword">int</span> <span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>my_addr<span class="token punctuation">,</span> <span class="token keyword">int</span> addrlen<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: sock file descriptor
- struct sockaddr *my_addr:
- addrlen : size của address, có thể sử dụng sizeof(struct sockaddr)
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><string.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><netinet/in.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><arpa/inet.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">MYPORT</span> <span class="token expression"><span class="token number">3490</span></span></span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> sockfd<span class="token punctuation">;</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> my_addr<span class="token punctuation">;</span> sockfd <span class="token operator">=</span> <span class="token function">socket</span><span class="token punctuation">(</span>PF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// do some error checking!</span> my_addr<span class="token punctuation">.</span>sin_family <span class="token operator">=</span> AF_INET<span class="token punctuation">;</span> <span class="token comment">// host byte order</span> my_addr<span class="token punctuation">.</span>sin_port <span class="token operator">=</span> <span class="token function">htons</span><span class="token punctuation">(</span>MYPORT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// short, network byte order</span> my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">.</span>s_addr <span class="token operator">=</span> <span class="token function">inet_addr</span><span class="token punctuation">(</span><span class="token string">"10.12.110.57"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_zero<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'�'</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// zero the rest of the struct</span> <span class="token comment">// don't forget your error checking for bind():</span> <span class="token function">bind</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>my_addr<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
3.3. Connect()
Kết nối với 1 máy chủ từ xa
1 2 3 4 5 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token keyword">int</span> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>serv_addr<span class="token punctuation">,</span> <span class="token keyword">int</span> addrlen<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: sock file desciptor
- struct sockaddr *serv_addr: Cấu trúc lưu địa chỉ và cổng đích kết nối
- addrlen: size địa chỉ, sử dụng sizeof(struct sockaddr)
Hàm này sẽ trả về giá trị -1 nếu gặp lỗi.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><string.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><netinet/in.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">DEST_IP</span> <span class="token string">"10.12.110.57"</span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">DEST_PORT</span> <span class="token expression"><span class="token number">23</span></span></span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> sockfd<span class="token punctuation">;</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> dest_addr<span class="token punctuation">;</span> <span class="token comment">// will hold the destination addr</span> sockfd <span class="token operator">=</span> <span class="token function">socket</span><span class="token punctuation">(</span>PF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// do some error checking!</span> dest_addr<span class="token punctuation">.</span>sin_family <span class="token operator">=</span> AF_INET<span class="token punctuation">;</span> <span class="token comment">// host byte order</span> dest_addr<span class="token punctuation">.</span>sin_port <span class="token operator">=</span> <span class="token function">htons</span><span class="token punctuation">(</span>DEST_PORT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// short, network byte order</span> dest_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">.</span>s_addr <span class="token operator">=</span> <span class="token function">inet_addr</span><span class="token punctuation">(</span>DEST_IP<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>dest_addr<span class="token punctuation">.</span>sin_zero<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'�'</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// zero the rest of the struct</span> <span class="token comment">// don't forget to error check the connect()!</span> <span class="token function">connect</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>dest_addr<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
3.4. Listen()
Đợi các kết nối từ xa đến và xử lý
1 2 3 4 5 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token keyword">int</span> <span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">int</span> backlog<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: sock file descriptor
- backlog: số kết nối được gửi đến trên hàng chờ đợi được xử lý
Trả về fd hoặc giá trị -1 nếu gặp lỗi
Vì hàm listen() nhận kết nối từ 1 host khác, nên cần thiết lập port mà ta nhận vào. Vì vậy quá trình sẽ là:
- socket() => bind() => listen() => accept()
Chúng ta sẽ nói về hàm accept() ở phần dưới.
3.5. Accept()
Chấp nhận kết nối tới và trả về 1 file desciptor (cùng giá trị với fd của listen), sử dụng để gửi và nhận data với 2 func send() và recv().
1 2 3 4 5 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token keyword">int</span> <span class="token function">accept</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span>addr<span class="token punctuation">,</span> <span class="token class-name">socklen_t</span> <span class="token operator">*</span>addrlen<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: fd của listen()
- struct sockaddr *addr: con trỏ trỏ đến cấu trúc lưu trữ địa chỉ struct sockaddr_in
- socklen_t *addrlen: con trỏ trỏ đến biến lưu trữ sizeof(struct sockaddr_in)
Trả về fd với sử dụng cho send() và recv() ở phần dưới
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><string.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/types.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><sys/socket.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><netinet/in.h></span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">MYPORT</span> <span class="token expression"><span class="token number">3490</span> </span><span class="token comment">// the port users will be connecting to</span></span> <span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">BACKLOG</span> <span class="token expression"><span class="token number">10</span> </span><span class="token comment">// how many pending connections queue will hold</span></span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> new_fd<span class="token punctuation">;</span> <span class="token comment">// listen on sock_fd, new connection on new_fd</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> my_addr<span class="token punctuation">;</span> <span class="token comment">// my address information</span> <span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span> their_addr<span class="token punctuation">;</span> <span class="token comment">// connector's address information</span> <span class="token keyword">int</span> sin_size<span class="token punctuation">;</span> sockfd <span class="token operator">=</span> <span class="token function">socket</span><span class="token punctuation">(</span>PF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// do some error checking!</span> my_addr<span class="token punctuation">.</span>sin_family <span class="token operator">=</span> AF_INET<span class="token punctuation">;</span> <span class="token comment">// host byte order</span> my_addr<span class="token punctuation">.</span>sin_port <span class="token operator">=</span> <span class="token function">htons</span><span class="token punctuation">(</span>MYPORT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// short, network byte order</span> my_addr<span class="token punctuation">.</span>sin_addr<span class="token punctuation">.</span>s_addr <span class="token operator">=</span> INADDR_ANY<span class="token punctuation">;</span> <span class="token comment">// auto-fill with my IP</span> <span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>my_addr<span class="token punctuation">.</span>sin_zero<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'�'</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// zero the rest of the struct</span> <span class="token comment">// don't forget your error checking for these calls:</span> <span class="token function">bind</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>my_addr<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">listen</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> BACKLOG<span class="token punctuation">)</span><span class="token punctuation">;</span> sin_size <span class="token operator">=</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr_in</span><span class="token punctuation">)</span><span class="token punctuation">;</span> new_fd <span class="token operator">=</span> <span class="token function">accept</span><span class="token punctuation">(</span>sockfd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> <span class="token class-name">sockaddr</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>their_addr<span class="token punctuation">,</span> <span class="token operator">&</span>sin_size<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
3.6. Send() và Recv()
Send()
1 2 | <span class="token keyword">int</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">void</span> <span class="token operator">*</span>msg<span class="token punctuation">,</span> <span class="token keyword">int</span> len<span class="token punctuation">,</span> <span class="token keyword">int</span> flags<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: fd của host muốn gửi dữ liệu, có thể là fd được trả về bởi socket() hoặc accept()
- const void *msg: data cần gửi
- int len: Độ lớn của dữ liệu tính theo byte
- int flags: Đặt giá trị bằng 0
Hàm trả về số byte được gửi đi, gửi hết nếu số byte nhở hơn 1K. So sánh giá trị trả về với int len để biết dữ liệu gửi hết chưa và xử lý phần còn lại.
Recv()
Nhận dữ liệu được gửi đến
1 2 | <span class="token keyword">int</span> <span class="token function">recv</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>buf<span class="token punctuation">,</span> <span class="token keyword">int</span> len<span class="token punctuation">,</span> <span class="token keyword">unsigned</span> <span class="token keyword">int</span> flags<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: fd của nơi gửi
- void *buf: buffer chứa dữ liệu
- int len: độ lớn dữ liệu tối đa nhận vào
- flags đặt thành 0
Hàm trả về -1 nếu xảy ra lỗi, 0 nếu kết nối bị đóng và giá trị khác là số byte nhận được
3.7. Close() và shutdown()
Close()
close(sockfd)
- sockfd: fd muốn đóng kết nối, ngưng gửi và nhận dữ liệu
shutdown()
1 2 | <span class="token keyword">int</span> <span class="token function">shutdown</span><span class="token punctuation">(</span><span class="token keyword">int</span> sockfd<span class="token punctuation">,</span> <span class="token keyword">int</span> how<span class="token punctuation">)</span><span class="token punctuation">;</span> |
- sockfd: fd muốn đóng kết nối
- how: cách đóng (0-ngưng nhận, 1-ngưng gửi, 2-ngưng nhận và gửi)
4. Chuyển đổi giữa Host name và IP address
5. Xử lý lỗi trong socket
Để in lỗi trong quá trình kết nối hay sử dụng các function, ta sử dụng hàm perror()
và herror()
trong thư viện errno.h
Ví dụ khi gặp lỗi trả về -1 trong hàm socket(), ta thực hiện in lỗi bằng hàm perror(“socket”);
Example:
1 2 3 4 5 | <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>sockfd <span class="token operator">=</span> <span class="token function">socket</span><span class="token punctuation">(</span>PF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">perror</span><span class="token punctuation">(</span><span class="token string">"socket"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Đổi với các function xử lý DNS (ở phần 4), sử dụng hàm herror để in ra lỗi.
Example:
1 2 3 | <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>he<span class="token operator">=</span><span class="token function">gethostbyname</span><span class="token punctuation">(</span><span class="token string">"facebook.com"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// get the host info </span> <span class="token function">herror</span><span class="token punctuation">(</span><span class="token string">"gethostbyname"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |