今天我們介紹如何編寫Linux下的TCP程序,關於UDP程序可以參考這裡:http://www.linuxidc.com/Linux/2012-06/61801.htm
本文絕大部分是參考《Linux程序設計(第4版)》的第15章套接字
《Linux程序設計》第四版中文版PDF下載見 http://www.linuxidc.com/Linux/2011-08/41135.htm
服務器端的步驟如下:
1. socket: 建立一個socket
2. bind: 將這個socket綁定在某個文件上(AF_UNIX)或某個端口上(AF_INET),我們會分別介紹這兩種。
3. listen: 開始監聽
4. accept: 如果監聽到客戶端連接,則調用accept接收這個連接並同時新建一個socket來和客戶進行通信
5. read/write:讀取或發送數據到客戶端
6. close: 通信完成後關閉socket
客戶端的步驟如下:
1. socket: 建立一個socket
2. connect: 主動連接服務器端的某個文件(AF_UNIX)或某個端口(AF_INET)
3. read/write:如果服務器同意連接(accept),則讀取或發送數據到服務器端
4. close: 通信完成後關閉socket
上面是整個流程,我們先給出一個例子,具體分析會在之後給出。例子實現的功能是客戶端發送一個字符到服務器,服務器將這個字符+1後送回客戶端,客戶端再把它打印出來:
Makefile:
- all: tcp_client.c tcp_server.c
- gcc -g -Wall -o tcp_client tcp_client.c
- gcc -g -Wall -o tcp_server tcp_server.c
-
- clean:
- rm -rf *.o tcp_client tcp_server
tcp_server.c:
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- int main()
- {
- /* delete the socket file */
- unlink("server_socket");
-
- /* create a socket */
- int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
-
- struct sockaddr_un server_addr;
- server_addr.sun_family = AF_UNIX;
- strcpy(server_addr.sun_path, "server_socket");
-
- /* bind with the local file */
- bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
-
- /* listen */
- listen(server_sockfd, 5);
-
- char ch;
- int client_sockfd;
- struct sockaddr_un client_addr;
- socklen_t len = sizeof(client_addr);
- while(1)
- {
- printf("server waiting:\n");
-
- /* accept a connection */
- client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);
-
- /* exchange data */
- read(client_sockfd, &ch, 1);
- printf("get char from client: %c\n", ch);
- ++ch;
- write(client_sockfd, &ch, 1);
-
- /* close the socket */
- close(client_sockfd);
- }
-
- return 0;
- }
tcp_client.c:
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- int main()
- {
- /* create a socket */
- int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
-
- struct sockaddr_un address;
- address.sun_family = AF_UNIX;
- strcpy(address.sun_path, "server_socket");
-
- /* connect to the server */
- int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
- if(result == -1)
- {
- perror("connect failed: ");
- exit(1);
- }
-
- /* exchange data */
- char ch = 'A';
- write(sockfd, &ch, 1);
- read(sockfd, &ch, 1);
- printf("get char from server: %c\n", ch);
-
- /* close the socket */
- close(sockfd);
-
- return 0;
- }
如果我們首先運行tcp_client,會提示沒有這個文件:
因為我們是以AF_UNIX方式進行通信的,這種方式是通過文件來將服務器和客戶端連接起來的,因此我們應該先運行tcp_server,創建這個文件,默認情況下,這個文件會創建在當前目錄下,並且第一個s表示它是一個socket文件:
程序運行的結果如下圖: