LwIP Application Development Notes nine: LwIP no TELNET server operating system

  We have already achieved a TCP server and client-based RAW API, to achieve HTTP applications are based on this. Next, we implement a TCP, Telnet server-based applications.

1 , the Telnet protocol Introduction

  Telnet protocol is TCP / IP protocol suite one, is the main way Internet standard protocols and remote login service. It provides the ability to complete the work of the remote host on a local computer user. Using the telnet program on the user's computer terminal, with which is connected to the server. The end user can enter commands in the telnet program, these commands will run on the server, just as input directly on the server console. You may be able to control the server locally. To start a telnet session, you must enter a user name and password to login server. Telnet is a common way to remotely control Web servers.

  Telnet is a protocol on the application layer --- the OSI 7 layer model, is provided to connect to a remote host terminal emulation TCP / IP protocol by creating virtual terminal. The agreement must be authenticated by user name and password, a standard protocol for remote login Internet services. Telnet protocol can use the local computer used by the user terminal into a remote host system. It provides three basic services:

  • Telnet is defined a virtual terminal provides a standard network interface to the remote system. The client does not have to learn more about the remote system, they simply constructed using a standard interface program;
  • Including a Telnet client and server mechanism allows the negotiation options, but it also provides a set of standard options;.
  • Symmetric processing ends Telnet connection, i.e. not forced Telnet client input from the keyboard, the client is not forced on the screen display output.

2 , TELNET server design

  Telnet is a remote login based on TCP, Telnet protocol is also assigned a fixed port 23, here we are with the port to achieve a Telnet server. The server can provide access to multiple clients.

 

  We want to achieve this Telnet server is a relatively simple design. When the client successfully linked to a server, the server will prompt the user to log on, after the successful landing can send commands to the server, when sending a different command, the server gives a different response. The specific operation flow is designed as follows:

 

  From a flow chart of the above fact, we see the Telnet server design has been very clear. But there are two points to describe. The first is set on the connection status, where we will simply state is defined as two types: logged in and logged. If you are logged press command interaction to resolve. If you are not logged press login password to resolve.

  On the other hand, in order to achieve command interaction, we need to set the command to the Telnet server. We simply set the six kinds of commands: "hello", "date", "time", "version", "quit" and "help" commands. In fact, we realize Telnet server mainly deal with: how to receive and respond to these commands.

3 , TELNET server implementation

  We have designed the basic functions of Telnet servers. The next step is how to achieve it. We have to realize the underlying TCP server front. So realize his focus is the design of the Telnet server we.

  We realize still using ordinary TCP server structure to achieve the Telnet server, only on the information processing callback function is more complex. There is the port we have adopted the usual Telnet port. First of all it must be initialized Telnet server.

 1 /* TELNET服务器初始化配置*/
 2 void Telnet_Server_Initialization(void)
 3 {
 4   struct tcp_pcb *pcb;                            
 5  
 6   /* 生成一个新的TCP控制块 */
 7   pcb = tcp_new();                                   
 8  
 9   /* 控制块邦定到本地IP和对应端口 */
10   tcp_bind(pcb, IP_ADDR_ANY, TCP_TELNET_SERVER_PORT);      
11  
12   /* 服务器进入侦听状态 */
13   pcb = tcp_listen(pcb);                       
14  
15   /* 注册服务器accept回调函数 */
16   tcp_accept(pcb, TelnetServerAccept);                                       
17 }

  其实初始化部分就是我们已经熟悉的TCP服务器的初始化,只是使用了Telnet的惯用端口。接下来就是实现在初始化中注册的Telnet服务器接收回调函数。该函数为tcp_accept_fn类型,注册到了监听控制块的accept字段。在服务器上有新连接建立时就会被内核调用。

 1 /* TELNET接收回调函数,客户端建立连接后,本函数被调用 */
 2 static err_t TelnetServerAccept(void *arg, struct tcp_pcb *pcb, err_t err)
 3 {    
 4   u32_t remote_ip;
 5   char linkInfo [100];
 6   u8_t iptab[4];
 7   telnet_conn_arg *conn_arg = NULL;
 8   remote_ip = pcb->remote_ip.addr;
 9  
10   iptab[0] = (u8_t)(remote_ip >> 24);
11   iptab[1] = (u8_t)(remote_ip >> 16);
12   iptab[2] = (u8_t)(remote_ip >> 8);
13   iptab[3] = (u8_t)(remote_ip);
14  
15   //生成登录提示信息
16   sprintf(linkInfo, "Welcome to Telnet! your IP:Port --> [%d.%d.%d.%d:%d]\r\n", \
17                    iptab[3], iptab[2], iptab[1], iptab[0], pcb->remote_port);  
18  
19   conn_arg = mem_calloc(sizeof(telnet_conn_arg), 1);
20   if(!conn_arg)
21   {
22     return ERR_MEM;
23   }
24  
25   conn_arg->state = TELNET_SETUP;
26   conn_arg->client_port = pcb->remote_port;
27   conn_arg->bytes_len = 0;
28   memset(conn_arg->bytes, 0, MAX_MSG_SIZE);
29  
30   tcp_arg(pcb, conn_arg);
31  
32   /* 注册Telnet服务器连接错误回调函数 */
33   tcp_err(pcb, TelnetServeConnectError);
34   /* 注册Telnet服务器消息处理回调函数*/
35   tcp_recv(pcb, TelnetServerCallback);
36  
37   /* 连接成功,发送登录提示信息 */ 
38   tcp_write(pcb, linkInfo, strlen(linkInfo), 1);
39   tcp_write(pcb, LOGIN_INFO, strlen(LOGIN_INFO), 1);
40  
41   return ERR_OK;
42 }

  在这个函数中,我们实现的功能主要是三方面:注册Telnet服务器消息处理回调函数;注册Telnet服务器连接错误回调函数;初始化Telnet服务器的状态。这个初始化是在连接建立后,Telnet服务器与客户端的交互初始化,比如登录状态,用户提示等。

  在上面的函数中,我们注册了两个回调函数,接下来必然就是实现这两个函数。我们先来实现Telnet服务器信息处理回调函数。这个函数其实就是我们前面注册过的TCP服务器数据接收处理函数。这个函数是tcp_recv_fn类型。这是使用RAW API实现TCP服务器最重要的函数,因为我们实现的TCP服务器究竟有什么功能,完全依赖于这个函数及其所调用的函数。

 1 /* TELNET服务器信息处理回调函数,在有消息需要处理时,调用此函数 */
 2 static err_t TelnetServerCallback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
 3 {
 4   telnet_conn_arg *conn_args = (telnet_conn_arg *)arg;
 5   char sndbuf[50];
 6   int strlen = 0;
 7   int ret = 0;
 8  
 9   if(NULL == conn_args || pcb->remote_port != conn_args->client_port)
10   {
11     if(p!= NULL)
12     {
13       pbuf_free(p);
14     }
15     return ERR_ARG;
16   }
17  
18   if (p != NULL)
19   {       
20     /* 更新接收窗口 */
21     tcp_recved(pcb, p->tot_len);
22  
23     ret = TelnetCommandInput(pcb, conn_args, p);
24  
25     if(ret == 1)//是完整命令
26     {
27       switch(conn_args->state)
28       {
29       case TELNET_SETUP:
30         {
31           if(strcmp(conn_args->bytes,PASSWORD) == 0)//密码正确
32           {
33             strlen = sprintf(sndbuf,"##Hello! This is an LwIP-based Telnet Server##\r\n");
34             tcp_write(pcb, sndbuf, strlen,TCP_WRITE_FLAG_COPY);
35             strlen = sprintf(sndbuf,"##Created by Moonan...                      ##\r\n");
36             tcp_write(pcb, sndbuf, strlen,TCP_WRITE_FLAG_COPY);
37             strlen = sprintf(sndbuf,"##Enter help for help.  Enter quit for quit.##\r\n");
38             tcp_write(pcb, sndbuf, strlen,TCP_WRITE_FLAG_COPY);
39             strlen = sprintf(sndbuf,"LwIP Telnet>");
40             tcp_write(pcb,sndbuf,strlen, 1);
41  
42             conn_args->state = TELNET_CONNECTED;//转换状态
43           }
44           else//密码错误,提示重新登录
45           {
46             strlen = sprintf(sndbuf,"##PASSWORD ERROR! Try again:##\r\n");
47             tcp_write(pcb, sndbuf, strlen,TCP_WRITE_FLAG_COPY);
48           }
49           memset(conn_args->bytes, 0, MAX_MSG_SIZE);
50           conn_args->bytes_len = 0;
51           break;
52         }
53       case TELNET_CONNECTED:
54         {
55           if(TelnetCommandParse(pcb, conn_args->bytes) == 0)
56           {
57             memset(conn_args->bytes, 0, MAX_MSG_SIZE);
58             conn_args->bytes_len = 0;
59           }
60           else
61           {
62             /* 服务器关闭连接 */
63             ServerCloseTelnetConnection(pcb);
64           }
65           break;
66         }
67       default:
68         {
69           break;
70         }
71       }
72     }
73     pbuf_free(p);
74   } 
75   else if (err == ERR_OK)
76   {
77     /* 服务器关闭连接 */
78     ServerCloseTelnetConnection(pcb);
79   }
80  
81   return ERR_OK;
82  
83 }

  在这个函数中,我们实现了Telnet服务器的各种功能,如登录验证,命令检查,命令响应等。已经具备一个Telnet服务器的基本框架。接下来还要实现Telnet连接错误回调函数。这个函数是tcp_err_fn类型,在这个程序中主要完成连接异常结束时的一些处理,可以释放一些必要的资源。在这个函数被内核调用时,连接实际上已经断开,相关控制块也已经被删除。所以在这个函数中我们可以重新初始化连接及其资源。

1 /* TELNET连接错误回调函数,连接故障时调用本函数 */
2 static void TelnetServeConnectError(void *arg, err_t err)
3 {
4   Telnet_Server_Initialization();
5 }

  至此,我们就实现了一个简单的Telnet服务器,当然它只是一个雏形,需要开发更复杂的功能则需要修改这几个回调函数。

4TELNET服务器总结

  我们已经实现了一个简单的Telnet服务器。当然,我们的目的主要是以此来学习基于LwIP的复杂的TCP应用。事实上理解了TCP服务器的实现机制,诸如此类基于TCP的高级应用协议并不是特别复杂的事情。

欢迎关注:

Guess you like

Origin www.cnblogs.com/foxclever/p/12115396.html