Socket 是常見的一種 Process之間的溝通方式(IPC, Inter-Porcess Communucation),
Socket 大致上可分兩種: 1. Internet domain socket 2. Unix domain socket
- Internet Domain Socket
- 適用於不同主機間的通訊. Socket 只要知道通訊另一方的 IP和 Port 就可以互相溝通, 這種 Socket是建立在網路傳輸協定之上
- Unix Domain Socket
- 用於一台主機的Process之間的溝通方式, 不需要建立在網路協定之上, 主要是基於 file system 發展.
- 與 Internet domain socket不一定的是, Unix Domain socket 需要知道的是 process 之間需要使用哪一個文件, 基於哪一個文件來做通訊(意旨相同的文件路徑)
- Unix Domain socket 適用於同一台主機的process之間的通訊, 事實上, Internet domain socket 也可以做到一樣的事情, 透過 lookback IP: 127.0.0.1, 但是 Unix domain socket用於IPC更有效率, 它不需要經過網路協定, 不需要 encode, decode 計算 checksum以及其他傳送封包時候要做的事情, 它只是將一個Process想要傳送的資料複製並傳送給另一個Process
- Unix domain socket 有 SOCK_DGRAM 或 SOCK_STREAM 兩種工作模式:
- SOCK_STREAM: 提供一個序列化的連接導向stream, 對應的 protocol為 TCP, 基本上常使用這個模式
- SOCK_DGRAM: 提供的是一個一個的 datagram, 對應的 protocol 是 UDP
- Unix domain socket 是全雙工運作, 下圖為 SOCK_STREAM為例的工作流程:
- 舉例: Client端 輸入 command, Server端 收到 command 後, 回應訊息
- Client 端:
- 假設 Client 端輸入一個指令讓電話撥出 dial tone ~# sip_config StartTones 0 0
- sip_config.c int main()
- socket(PF_LOCAL, SOCK_STREAM, 0)
- #define socket_path "/tmp/socket"
- name.sun_family = AF_LOCAL; strcpy(name.sun_path, socket_path);
- connect(socket_fd, &name, SUN_LEN(&name))
- write(socket_fd, buf, sizeof(buf))
- sip_config 是已經 compile 好的一個執行檔, 也就是透過 sip_config 做連線的動作, 並且將會面的訊息傳遞給 Server 端
- Server 端:
- sip_core.c > pthread_create(SIP_CORE_ProcUI) > 建 socket 等 client 的 command request
- socket(PF_LOCAL, SOCK_STREAM, 0)
- name.sun_family = AF_LOCAL
- #define socket_path "/tmp/socket"
- strcpy(name.sun_path, socket_path)
- bind(s, (struct sockaddr *)&name, SUN_LEN(&name))
- listen(s, num_client); // #define num_client 6
- 利用 while(1) + select 等訊息
- FD_ZERO() > FD_SET
- ret = select(AdminSocket + 1, &ibits, 0, 0, &timeout)
- ret > 0 → FD_ISSET(AdminSocket, &ibits)
- accept(AdminSocket, (struct sockaddr *)&client_name, &client_name_len)
- read(client_socket_fd, buffer, sizeof(buffer))
- close(client_socket_fd)
- sip_core.c > pthread_create(SIP_CORE_ProcUI) > 建 socket 等 client 的 command request
- 常用 function 說明
- int socket (int domain, int type, int protocol)
- 建立一個 socket file descriptor, socket 相關的function, 操作上都需要有一個 socket file descriptor才能針對特定的 domain socket 做處理
- domain: Internet domain: AF_INET or AF_INET6 Unix domain: AF_LOCAL
- type: SOCK_STREAM (tcp), SOCK_DGRAM(udp)
- protocol: IPPROTO_TCP, IPPROTO_UDP, 通常會設定為0, kernel 選擇 type 對應的 default protocol
- int bind (int sockfd, struct sockaddr *local_addr, socklen_t addrlen);
- 把一個特定的位址(IP address, Port) 綁定給 socket
- int listen(int sockfd, int backlog)
- sockfd: 想要設定的 socket file descriptor
- backlog: 設定最多能有幾個人可以連到 server
- int accpet(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
- Server listen 到 Client 的 Request之後, 使用 accept()接收Request, 這樣連結就建立完成了.
- accept()被使用時, 它會為該Request產生出一個新的SOCKET, 並把這個Request從 listen queue剔除
- int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
- client 使用 connect() 跟 server 連接
- struct sockaddr *serv_addr: 儲存要連接的server資訊
- ssize_t write(int fd, const void *buf, size_t count)
- 把資料寫到特定的 file descriptor
- *buf: 想要寫入的資料
- ssize_t read(int fd, void *buf, size_t count);
- 從特定的 file descriptor讀取資料
- int select(int maxfds, fd_set *readfds, fd_set *writefds, fd_set errorfds, struct timeval *timeout)
- maxfds: 是一個整數值, 指集合中所有file decriptor的範圍, 意即所有 file descriptor的最大值加1
- int socket (int domain, int type, int protocol)
- 常用的 UDP Data gram 傳輸流程