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