IPC: (3) socket
Socket 為 Linux IPC (Inter-process communication) 的方式之一. process 可藉由 socket 傳遞資料至另一個 process. 以下以 AF_INET 作為範例來介紹 TCP 與 UDP.
TCP 與 UDP 皆以講解流程圖與 API 的用法為主. 完整範例 code 請點選 github 連結.
TCP
以下為 TCP server 與 client 端的建立通訊流程. 當中的 write 與 read 可以與 send 與 recv 替換. 範例 code 請參閱 github
TCP 流程圖 [1]
Server 與 client 透過 socket 來通訊的流程如下.
- Server 端:
- Client 端:
建立 socket 後, 藉由 bind() 綁上 ip 與 port. 執行 listen() 等待 client 的連線要求. 透過 accept() 接受要求後, 便可開始與 client 進行傳輸的動作.
建立 socket 後, 在 connect() 綁上 server 的 ip 與 port 進行連線. 當連線要求被接受後, 便可以進行傳輸.
TCP APIs
socket [2]
#include <sys/socket.h> sockfd = socket(int socket_family, int socket_type, int protocol);
socket_family: 為所用的 socket domain, 這邊採用網際網路的關係, 故選用 AF_INET.
socket_type: 由於選用 TCP, 所以使用 SOCK_STREAM.
protocol: 預設數值為 0
bind [3]
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
sockfd: 為所要用的 socket fd.
addr: 設定此 socket 所要綁定的 ip 與 port.
addrlen: 為 addr 的大小
在撰寫的時候, 通常都是用 sockaddr_in 資料結構來填寫 ip 與 port. 之後再透過資料轉換的方式轉成 bind() 所需的格式. 詳細的解說可參考[9]
listen [4]
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int listen(int sockfd, int backlog);
sockfd: 所要進行 listen 的 socket fd. 其類型須為 SOCK_STREAM 或 SOCK_SEQPACKET.
backlog: 在 queue 當中, 等待進行處理的 connection 數量.
accept [5]
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd: 正在進行 listen 的 socket fd.
addr: 儲存 remote 端的 ip address 與 port.
addrlen: addr 的大小.
connect [6]
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd: 所建立的 socket fd.
addr: 所要連接的 server ip 與 port 資訊.
addrlen: addr 的大小
UDP
底下為 UDP server 與 client 端的建立通訊流程, 範例 code 請參閱 github
UDP 流程圖 [1]
Server 與 client 建立 socket 來通訊的流程如下圖
- Server 端:
- Client 端:
建立 socket 後, 藉由 bind() 綁上 ip 與 port. 便可以開始接收(recvfrom())與傳輸(sendto())資料. 其中傳送者的資訊可以在 packet 的標頭得知, 不用擔心資料不知道要回傳資料給誰.
建立 socket 後, 直接在 sendto() 帶入 server 的 ip 與 port, 便可以把資料直接傳遞過去.
UDP APIs
socket [2]
#include <sys/socket.h> sockfd = socket(int socket_family, int socket_type, int protocol);
socket_family: 為所用的 socket domain, 這邊採用網際網路的關係, 故選用 AF_INET.
socket_type: 由於選用 UDP, 所以使用 SOCK_DGRAM.
protocol: 預設數值為 0
bind [3]
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
sockfd: 為所要用的 socket fd.
addr: 設定此 socket 所要綁定的 ip 與 port.
addrlen: 為 addr 的大小
在撰寫的時候, 通常都是用 sockaddr_in 資料結構來填寫 ip 與 port. 之後再透過資料轉換的方式轉成 bind() 所需的格式. 詳細的解說可參考[9]
recvfrom [7]
#include <sys/types.h> #include <sys/socket.h> ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
sockfd: bind 所使用的 socket fd.
buf: 存在資料的 address
len: buf 的大小
flags: 預設為 0
src_addr: 存在 remote 端的資訊.
addrlen: src_addr 的大小
recvfrom [8]
#include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
sockfd: process 所使用的 socket fd.
buf: 存在資料的 address
len: buf 的大小
flags: 預設為 0
src_addr: 存在 remote 端的資訊.
addrlen: src_addr 的大小
留言
張貼留言