1 /*
2 * Copyright (C) 2022 HiHope Open Source Organization .
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http:// www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 *
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include "net_common.h"
23
24 static char request[128] = "";
TcpServerTest(unsigned short port)25 void TcpServerTest(unsigned short port)
26 {
27 ssize_t retval = 0;
28 int backlog = 1;
29 int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
30 int connfd = -1;
31
32 struct sockaddr_in clientAddr = {0};
33 socklen_t clientAddrLen = sizeof(clientAddr);
34 struct sockaddr_in serverAddr = {0};
35 serverAddr.sin_family = AF_INET;
36 serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
37 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入, 0.0.0.0
38
39 retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
40 if (retval < 0) {
41 printf("bind failed, %ld!\r\n", retval);
42 close(sockfd);
43 }
44 printf("bind to port %u success!\r\n", port);
45
46 retval = listen(sockfd, backlog); // 开始监听
47 if (retval < 0) {
48 printf("listen failed!\r\n");
49 printf("do_cleanup...\r\n");
50 close(sockfd);
51 }
52 printf("listen with %d backlog success!\r\n", backlog);
53
54 // 接受客户端连接,成功会返回一个表示连接的 socket , clientAddr 参数将会携带客户端主机和端口信息 ;失败返回 -1
55 // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
56 // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
57 // 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型
58 // liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
59 connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
60 if (connfd < 0) {
61 printf("accept failed, %d, %d\r\n", connfd, errno);
62 printf("do_cleanup...\r\n");
63 close(sockfd);
64 }
65 printf("accept success, connfd = %d!\r\n", connfd);
66 printf("client addr info: host = %s, port = %d\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
67
68 // 后续 收、发 都在 表示连接的 socket 上进行;
69 retval = recv(connfd, request, sizeof(request), 0);
70 if (retval < 0) {
71 printf("recv request failed, %ld!\r\n", retval);
72 printf("do_cleanup...\r\n");
73 close(sockfd);
74 }
75 printf("recv request{%s} from client done!\r\n", request);
76
77 retval = send(connfd, request, strlen(request), 0);
78 if (retval <= 0) {
79 printf("send response failed, %ld!\r\n", retval);
80 printf("do_cleanup...\r\n");
81 close(sockfd);
82 }
83 printf("send response{%s} to client done!\r\n", request);
84
85 do_disconnect:
86 sleep(1);
87 close(connfd);
88 sleep(1); // for debug
89 SERVER_TEST_DEMO(TcpServerTest);