1 /*
2 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * limitations under the License.
14 */
15
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include "lwip/sockets.h"
20 #include "net_demo.h"
21
22 static char g_request[128] = "Hello,I am Lwip";
23
TcpServerTest(unsigned short port)24 void TcpServerTest(unsigned short port)
25 {
26 int backlog = 1;
27 int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
28
29 struct sockaddr_in clientAddr = {0};
30 socklen_t clientAddrLen = sizeof(clientAddr);
31 struct sockaddr_in serverAddr = {0};
32 serverAddr.sin_family = AF_INET;
33 serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
34 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入, 0.0.0.0
35
36 ssize_t retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
37 if (retval < 0) {
38 printf("bind failed, %ld!\r\n", retval);
39 printf("do_cleanup...\r\n");
40 lwip_close(sockfd);
41 }
42 printf("bind to port success!\r\n");
43
44 retval = listen(sockfd, backlog); // 开始监听
45 if (retval < 0) {
46 printf("listen failed!\r\n");
47 printf("do_cleanup...\r\n");
48 lwip_close(sockfd);
49 }
50 printf("listen with %d backlog success!\r\n", backlog);
51
52 // 接受客户端连接,成功会返回一个表示连接的 socket , clientAddr 参数将会携带客户端主机和端口信息 ;失败返回 -1
53 // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
54 // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
55 // 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型
56 // liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
57 int connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
58 if (connfd < 0) {
59 printf("accept failed, %d, %d\r\n", connfd, errno);
60 printf("do_cleanup...\r\n");
61 lwip_close (sockfd);
62 }
63 printf("accept success, connfd = %d!\r\n", connfd);
64 printf("client addr info: host = %s, port = %d\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
65
66 // 后续 收、发 都在 表示连接的 socket 上进行;
67 retval = recv(connfd, g_request, sizeof(g_request), 0);
68 if (retval < 0) {
69 printf("recv g_request failed, %ld!\r\n", retval);
70 sleep(1);
71 lwip_close(connfd);
72 sleep(1); // for debug
73 lwip_close(sockfd);
74 }
75 printf("recv g_request{%s} from client done!\r\n", g_request);
76
77 retval = send(connfd, g_request, strlen(g_request), 0);
78 if (retval <= 0) {
79 printf("send response failed, %ld!\r\n", retval);
80 sleep(1);
81 lwip_close(connfd);
82 sleep(1); // for debug
83 lwip_close(sockfd);
84 }
85 printf("send response{%s} to client done!\r\n", g_request);
86 }
87
NetDemoTest(unsigned short port, const char* host)88 void NetDemoTest(unsigned short port, const char* host)
89 {
90 (void) host;
91 printf("TcpServerTest start\r\n");
92 printf("I will listen on \r\n");
93 TcpServerTest(port);
94 printf("TcpServerTest done!\r\n");
95 }
96