本文将介绍一个简单 Linux TCP 服务器程序的实现,功能是只要客户端发送连接请求过来,就发送"Hello World"给客户端。
在 TCP/IP 协议中,"IP+端口" 可以唯一标识网络通讯中的一个进程。套接字(socket)本身有插座的意思,它是用于进程间网络通讯的一种特殊文件类型,这种文件跟普通文件不一样,普通文件需要存储在硬盘上,而 socket 文件是借助内核缓冲区形成的伪文件。在 Linux 读写普通文件时,我们先使用 open 函数打开文件然后获取文件句柄 fd,然后调用 read 函数就可以读取文件内容,调用 write 函数就可以往文件写入内容。socket 也可以类似理解为这样的文件描述符,可以理解为:如果网络通讯中两个进程要通讯就需要借助套接字(socket)来实现。
假设现在服务器创建了一个 socket 并且处于监听状态,客户端也创建了一个 socket 与服务器建立起连接,然后客户端就可以通过 write 给服务器发送数据,通过 read 读取服务器发送来的数据。
C/S 模型又称为客户端/服务器模型,对于 TCP 客户端/服务器模型开发一般如下图所示。
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8
9 #define SERVER_PORT 8080
10
11 int main()
12 {
13 int listen_fd = socket(AF_INET,SOCK_STREAM,0);
14 int conn_fd = 0;
15 char data[] = "Hello World!";
16
17 struct sockaddr_in server_addr;
18 memset(&server_addr,0,sizeof(server_addr));
19 server_addr.sin_family = AF_INET;
20 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
21 server_addr.sin_port = htons(SERVER_PORT);
22
23 bind(listen_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
24 listen(listen_fd,32);
25
26 while(1)
27 {
28 conn_fd = accept(listen_fd,(struct sockaddr *)NULL,NULL);
29 write(conn_fd,data,strlen(data));
30 close(conn_fd);
31 }
32 close(listen_fd);
33
34 return 0;
35 }
程序讲解
1. 首先调用一个 socket 函数创建一个监听套接字,第一个参数 AF_INET 代表是 IPv4 地址,第二个参数 SOCK_STREAM 代表流式协议,第三个参数 0 代表默认协议,这里是 TCP。
2. 将套接字与具体的 IP 和端口绑定,需要调用 bind 函数,bind 函数的第一个参数是需要绑定的 socket,第二个参数是一个 struct sockaddr 类型的指针,第三个参数是 struct sockaddr 类型的指针指向的数据长度。可以看到,创建了 struct sockaddr_in 结构体后,将其程序 sin_family 指定为 AF_INET,即 IPv4 类型;将 sin_addr.s_addr 指定为 INADDR_ANY 代表使用主机的任意一个地址(因为一个电脑可以有多个网卡,拥有多个 IP 地址);将 sin_port 指定为 8080,这样该套接字就与一个本地 IP 和 8080 端口绑定起来了。
3.调用 listen 函数指定处于连接就绪队列的连接数最大值。
4.在 while(1) 中 accept 阻塞等待客户端发送连接请求过来,一旦成功与客户端连接,accept 函数就返回一个与客户端通讯的通讯套接字(注意监听套接字与通讯套接字不同),然后往通讯套接字写入数据,再调用 close 关闭连接。
关于上述一些 API 的具体含义将会在后续文章做深入讲解,这里只需要先简单了解含义即可。
编写完 server.c 文件后,需要编译产生可执行文件然后运行。
编译:gcc server.c -o server
运行:./server
运行 server 程序后,需要有对应的客户端程序去发起访问,这里介绍一个好用的客户端工具:telnet。
Ubuntu 下安装 telnet:sudo apt-get install telnet
telnet 使用,在命令行模式下输入:telnet IP地址 端口,如 telnet 127.0.0.1 8080 就可以发起对本地 8080 端口的访问了。
如上,使用 telnet 往 127.0.0.1 的 8080 端口建立连接后,客户端收到了 Hello,world!,这句话是服务器程序 write 函数调用的结果,然后显示 Connection closed by foreign ost,这是因为每次连接后服务器发送完 Hello,world! 就 close 掉这个 socket 了。