今天我们介绍如何编写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文件:
程序运行的结果如下图: