## 6.4 TCP编程简单示例
服务器首先进行初始化操作:调用函数socket创建一个套接字,函数bind将这个套接字与服务器的公认地址绑定在一起,函数listen将这个套接字换成倾听套接字,然后调用函数accept来等待客户机的请求。过了一段时间后,客户机启动,调用socket创建一个套接字,然后调用函数connect来与服务器建立连接。连接建立之后,客户机和服务器通过读、写套接字来进行通信。
### 6.**4.1** 服务器端代码
参考:TCP/server_line.c
```c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9#include <signal.h>
10
11#define SERVER_PORT 8180
12#define C_QUEUE 10
13
14/************************************************************
15*函数功能描述:从8180端口接收客户端数据
16*输入参数:无
17*输出参数:打印客户IP以及发来的信息
18*返回值:无
19*修改日期 版本号 修改人 修改内容
20*2020/05/13 v1.0.0 zonghzha reat
21*************************************************************/
22
23int main(int argc, char **argv)
24{
25 char buf[512];
26 int len;
27 int duty_socket;
28 int customer_socket;
29 struct sockaddr_in socket_server_addr;
30 struct sockaddr_in socket_client_addr;
31 int ret;
32 int addr_len;
33
34 signal(SIGCHLD, SIG_IGN);
35
36 /* 服务器端开始建立socket描述符 */
37 duty_socket = socket(AF_INET, SOCK_STREAM, 0);
38 if (duty_socket == -1)
39 {
40 printf("socket error");
41 return -1;
42 }
43
44 /* 服务器端填充 sockaddr_in结构 */
45 socket_server_addr.sin_family = AF_INET;
46 /* 端口号转换为网络字节序 */
47 socket_server_addr.sin_port = htons(SERVER_PORT);
48 /* 接收本机所有网口的数据 */
49 socket_server_addr.sin_addr.s_addr = INADDR_ANY;
50 memset(socket_server_addr.sin_zero, 0, 8);
51
52 /* 捆绑sockfd描述符 */
53 ret = bind(duty_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
54 if (ret == -1)
55 {
56 printf("bind error!\n");
57 return -1;
58 }
59 ret = listen(duty_socket, C_QUEUE);
60 if (ret == -1)
61 {
62 printf("listen error!\n");
63 return -1;
64 }
65
66 while (1)
67 {
68 addr_len = sizeof(struct sockaddr);
69 /* 服务器阻塞,直到客户程序建立连接 */
70 customer_socket = accept(duty_socket, (struct sockaddr *)&socket_client_addr, &addr_len);
71 if (customer_socket != -1)
72 {
73 /*inet_ntoa的作用是将一个32位Ipv4地址转换为相应的点分十进制数串*/
74 printf("Get connect from %s\n", inet_ntoa(socket_client_addr.sin_addr));
75 }
76 if (!fork())
77 {
78 while (1)
79 {
80 memset(buf, 512, 0);
81 /*接收数据*/
82 len = recv(customer_socket, buf, sizeof(buf), 0);
83 buf[len] = '\0';
84 if (len <= 0)
85 {
86 close(customer_socket);
87 return -1;
88 }
89 else
90 {
91 printf("Get connect from %s, Msg is %s\n", inet_ntoa(socket_client_addr.sin_addr), buf);
92 }
93 }
94 }
95 }
96
97 close(duty_socket);
98 return 0;
99}
```
### 6.4.2 客户端代码
参考:TCP/client_line.c
```c
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9
10#define SERVER_PORT 8180
11/************************************************************
12*函数功能描述:向指定IP的8180端口发送数据
13*输入参数:点分十进制服务器IP
14*输出参数:无
15*返回值:无
16*修改日期 版本号 修改人 修改内容
17*2020/05/13 v1.0.0 zonghzha creat
18*************************************************************/
19
20int main(int argc, char **argv)
21{
22 unsigned char buf[512];
23 int len;
24 struct sockaddr_in socket_server_addr;
25 int ret;
26 int addr_len;
27 int client_socket;
28
29
30 if (argc != 2)
31 {
32 printf("Usage:\n");
33 printf("%s <server_ip>\n", argv[0]);
34 return -1;
35 }
36
37 /* 客户程序开始建立 sockfd描述符 */
38 client_socket = socket(AF_INET, SOCK_STREAM, 0);
39 if (client_socket == -1)
40 {
41 printf("socket error");
42 return -1;
43 }
44
45 /* 客户程序填充服务端的资料 */
46 socket_server_addr.sin_family = AF_INET;
47 /*主机字节序转换为网络字节序*/
48 socket_server_addr.sin_port = htons(SERVER_PORT);
49 if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0)
50 {
51 printf("invalid server ip\n");
52 return -1;
53 }
54 memset(socket_server_addr.sin_zero, 0, 8);
55 /* 客户程序发起连接请求 */
56 ret = connect(client_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
57 if (ret == -1)
58 {
59 printf("connect error!\n");
60 return -1;
61 }
62
63
64 while (1)
65 {
66 if (fgets(buf, sizeof(buf), stdin))
67 {
68 len = send(client_socket, buf, strlen(buf), 0);
69 if (len <= 0)
70 {
71 close(client_socket);
72 return -1;
73 }
74 }
75 }
76
77 close(client_socket);
78 return 0;
79}
```
### 6.4.3 Makefile文件
```c
all:server client
server:server.c
gcc $^ -o $@
client:client.c
gcc $^ -o $@
clean:
rm server client -f
(注意:命令语句的开头要用“Tab”键。)
```
### 6.4.4 执行
服务器端:
```c
./server
```
客户端:
```c
./client 127.0.0.1
```
客户端输入:
```c
good night
```
服务器端显示:
```c
Get connect from 127.0.0.1
Get connect from 127.0.0.1, Msg is good night
```
|