Appearance
RAW接口
但是这一个使用的时候代码的可读性比较差, 并且逻辑比较复杂
UDP
API
c
/**
* @ingroup udp_raw
* Creates a new UDP pcb which can be used for UDP communication. The
* pcb is not active until it has either been bound to a local address
* or connected to a remote address.
* @see MEMP_NUM_UDP_PCB
*
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @see udp_remove()
*/
struct udp_pcb * udp_new(void);
c
/**
* @ingroup udp_raw
* Removes and deallocates the pcb.
*
* @param pcb UDP PCB to be removed. The PCB is removed from the list of
* UDP PCB's and the data structure is freed from memory.
*
* @see udp_new()
*/
void udp_remove(struct udp_pcb *pcb);
c
/**
* @ingroup udp_raw
* Bind an UDP PCB.
*
* @param pcb UDP PCB to be bound with a local address ipaddr and port.
* @param ipaddr local IP address to bind with. Use IP_ANY_TYPE to
* bind to all local interfaces.
* @param port local UDP port to bind with. Use 0 to automatically bind
* to a random port between UDP_LOCAL_PORT_RANGE_START and
* UDP_LOCAL_PORT_RANGE_END.
*
* ipaddr & port are expected to be in the same byte order as in the pcb.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occurred.
* - ERR_USE. The specified ipaddr and port are already bound to by
* another UDP PCB.
*
* @see udp_disconnect()
*/
err_t udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
之后会使用这一个端口号进行获取数据
c
/**
* @ingroup udp_raw
* Sets the remote end of the pcb. This function does not generate any
* network traffic, but only sets the remote address of the pcb.
*
* @param pcb UDP PCB to be connected with remote address ipaddr and port.
* @param ipaddr remote IP address to connect with.
* @param port remote UDP port to connect with.
*
* @return lwIP error code
*
* ipaddr & port are expected to be in the same byte order as in the pcb.
*
* The udp pcb is bound to a random local port if not already bound.
*
* @see udp_disconnect()
*/
err_t udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port);
进行一个远程的连接, 连接以后可以发送数据
c
/**
* @ingroup udp_raw
* Remove the remote end of the pcb. This function does not generate
* any network traffic, but only removes the remote address of the pcb.
*
* @param pcb the udp pcb to disconnect.
*/
void udp_disconnect(struct udp_pcb *pcb);
c
/**
* @ingroup udp_raw
* Sends the pbuf p using UDP. The pbuf is not deallocated.
*
*
* @param pcb UDP PCB used to send the data.
* @param p chain of pbuf's to be sent.
*
* The datagram will be sent to the current remote_ip & remote_port
* stored in pcb. If the pcb is not bound to a port, it will
* automatically be bound to a random port.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occurred.
* - ERR_MEM. Out of memory.
* - ERR_RTE. Could not find route to destination address.
* - ERR_VAL. No PCB or PCB is dual-stack
* - More errors could be returned by lower protocol layers.
*
* @see udp_disconnect() udp_sendto()
*/
err_t
udp_send(struct udp_pcb *pcb, struct pbuf *p)
发送数据, 发送的时候使用pbuf
c
/**
* @ingroup udp_raw
* Set a receive callback for a UDP PCB.
* This callback will be called when receiving a datagram for the pcb.
*
* @param pcb the pcb for which to set the recv callback
* @param recv function pointer of the callback function
* @param recv_arg additional argument to pass to the callback function
*/
void
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg);
注册一个接收使用的函数
c/** * @brief UDP服务器回调函数 * @param arg :传入参数 * @param upcb:UDP控制块 * @param p : 网络数据包 * @param addr:IP地址 * @param port:端口号 * @retval 无 */ static void lwip_udp_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
这一个函数里面的pbuf可以获取接收的数据
实际使用
c
udppcb = udp_new();
if (udppcb) /* 创建成功 */
{
IP4_ADDR(&rmtipaddr, g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]);
err = udp_connect(udppcb, &rmtipaddr, LWIP_DEMO_PORT); /* UDP客户端连接到指定IP地址和端口号的服务器 */
if (err == ERR_OK)
{
err = udp_bind(udppcb, IP_ADDR_ANY, LWIP_DEMO_PORT); /* 绑定本地IP地址与端口号 */
if (err == ERR_OK) /* 绑定完成 */
{
udp_recv(udppcb,lwip_udp_callback, NULL); /* 注册接收回调函数 */
}
else res = 1;
}
else res = 1;
}
else res = 1;
TCP
实际使用的时候需要初始化这些回调函数
API
建立连接
c
/**
* @ingroup tcp_raw
* Creates a new TCP protocol control block but doesn't place it on
* any of the TCP PCB lists.
* The pcb is not put on any list until binding using tcp_bind().
* If memory is not available for creating the new pcb, NULL is returned.
* @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB
*
* @internal: Maybe there should be a idle TCP PCB list where these
* PCBs are put on. Port reservation using tcp_bind() is implemented but
* allocated pcbs that are not bound can't be killed automatically if wanting
* to allocate a pcb with higher prio (@see tcp_kill_prio())
*
* @return a new tcp_pcb that initially is in state CLOSED
*/
struct tcp_pcb * tcp_new(void);
c
/**
* @ingroup tcp_raw
* Binds the connection to a local port number and IP address. If the
* IP address is not given (i.e., ipaddr == IP_ANY_TYPE), the connection is
* bound to all local IP addresses.
* If another connection is bound to the same port, the function will
* return ERR_USE, otherwise ERR_OK is returned.
* @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB
*
* @param pcb the tcp_pcb to bind (no check is done whether this pcb is
* already bound!)
* @param ipaddr the local ip address to bind to (use IPx_ADDR_ANY to bind
* to any local address
* @param port the local port to bind to
* @return ERR_USE if the port is already in use
* ERR_VAL if bind failed because the PCB is not in a valid state
* ERR_OK if bound
*/
err_t tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
绑定一个本地端口, 用于进行连接
c
#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
/**
* @ingroup tcp_raw
* Set the state of the connection to be LISTEN, which means that it
* is able to accept incoming connections. The protocol control block
* is reallocated in order to consume less memory. Setting the
* connection to LISTEN is an irreversible process.
* When an incoming connection is accepted, the function specified with
* the tcp_accept() function will be called. The pcb has to be bound
* to a local port with the tcp_bind() function.
*
* The tcp_listen() function returns a new connection identifier, and
* the one passed as an argument to the function will be
* deallocated. The reason for this behavior is that less memory is
* needed for a connection that is listening, so tcp_listen() will
* reclaim the memory needed for the original connection and allocate a
* new smaller memory block for the listening connection.
*
* tcp_listen() may return NULL if no memory was available for the
* listening connection. If so, the memory associated with the pcb
* passed as an argument to tcp_listen() will not be deallocated.
*
* The backlog limits the number of outstanding connections
* in the listen queue to the value specified by the backlog argument.
* To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
*
* @param pcb the original tcp_pcb
* @param backlog the incoming connections queue limit
* @return tcp_pcb used for listening, consumes less memory.
*
* @note The original tcp_pcb is freed. This function therefore has to be
* called like this:
* tpcb = tcp_listen_with_backlog(tpcb, backlog);
*/
struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
实际限制了可以同时连接的个数, 默认是0xff最大值
c
/**
* @ingroup tcp_raw
* Used for specifying the function that should be called when a
* LISTENing connection has been connected to another host.
* @see MEMP_NUM_TCP_PCB_LISTEN and MEMP_NUM_TCP_PCB
*
* @param pcb tcp_pcb to set the accept callback
* @param accept callback function to call for this pcb when LISTENing
* connection has been connected to another host
*/
void
tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept);
/** Function prototype for tcp accept callback functions. Called when a new
* connection can be accepted on a listening pcb.
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param newpcb The new connection pcb
* @param err An error code if there has been an error accepting.
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*/
typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);
使用这一个函数设置一个连接的时候回调函数
c
/**
* @ingroup tcp_raw
* Connects to another host. The function given as the "connected"
* argument will be called when the connection has been established.
* Sets up the pcb to connect to the remote host and sends the
* initial SYN segment which opens the connection.
*
* The tcp_connect() function returns immediately; it does not wait for
* the connection to be properly setup. Instead, it will call the
* function specified as the fourth argument (the "connected" argument)
* when the connection is established. If the connection could not be
* properly established, either because the other host refused the
* connection or because the other host didn't answer, the "err"
* callback function of this pcb (registered with tcp_err, see below)
* will be called.
*
* The tcp_connect() function can return ERR_MEM if no memory is
* available for enqueueing the SYN segment. If the SYN indeed was
* enqueued successfully, the tcp_connect() function returns ERR_OK.
*
* @param pcb the tcp_pcb used to establish the connection
* @param ipaddr the remote ip address to connect to
* @param port the remote tcp port to connect to
* @param connected callback function to call when connected (on error,
the err calback will be called)
* @return ERR_VAL if invalid arguments are given
* ERR_OK if connect request has been sent
* other err_t values if connect request couldn't be sent
*/
err_t
tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
tcp_connected_fn connected);
/** Function prototype for tcp connected callback functions. Called when a pcb
* is connected to the remote side after initiating a connection attempt by
* calling tcp_connect().
*
* @param arg Additional argument to pass to the callback function (@see tcp_arg())
* @param tpcb The connection pcb which is connected
* @param err An unused error code, always ERR_OK currently ;-) @todo!
* Only return ERR_ABRT if you have called tcp_abort from within the
* callback function!
*
* @note When a connection attempt fails, the error callback is currently called!
*/
typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
连接另一个设备, 使用IP地址和对方的端口, 还需要一个连接成功的回调函数
发送数据
c
/**
* @ingroup tcp_raw
* Write data for sending (but does not send it immediately).
*
* It waits in the expectation of more data being sent soon (as
* it can send them more efficiently by combining them together).
* To prompt the system to send data now, call tcp_output() after
* calling tcp_write().
*
* This function enqueues the data pointed to by the argument dataptr. The length of
* the data is passed as the len parameter. The apiflags can be one or more of:
* - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
* for the data to be copied into. If this flag is not given, no new memory
* should be allocated and the data should only be referenced by pointer. This
* also means that the memory behind dataptr must not change until the data is
* ACKed by the remote host
* - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted,
* the PSH flag is set in the last segment created by this call to tcp_write.
* If this flag is given, the PSH flag is not set.
*
* The tcp_write() function will fail and return ERR_MEM if the length
* of the data exceeds the current send buffer size or if the length of
* the queue of outgoing segment is larger than the upper limit defined
* in lwipopts.h. The number of bytes available in the output queue can
* be retrieved with the tcp_sndbuf() function.
*
* The proper way to use this function is to call the function with at
* most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
* the application should wait until some of the currently enqueued
* data has been successfully received by the other host and try again.
*
* @param pcb Protocol control block for the TCP connection to enqueue data for.
* @param arg Pointer to the data to be enqueued for sending.
* @param len Data length in bytes
* @param apiflags combination of following flags :
* - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
* - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will not be set on last segment sent,
* @return ERR_OK if enqueued, another err_t on error
*/
err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
发送数据但是不是立即发送, 可以把多个数据进行合并
c
/**
* @ingroup tcp_raw
* Specifies the callback function that should be called when data has
* successfully been received (i.e., acknowledged) by the remote
* host. The len argument passed to the callback function gives the
* amount bytes that was acknowledged by the last acknowledgment.
*
* @param pcb tcp_pcb to set the sent callback
* @param sent callback function to call for this pcb when data is successfully sent
*/
void tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
设置发送结束的回调函数
c
/**
* @ingroup tcp_raw
* Find out what we can send and send it
*
* @param pcb Protocol control block for the TCP connection to send data
* @return ERR_OK if data has been sent or nothing to send
* another err_t on error
*/
err_t tcp_output(struct tcp_pcb *pcb)
把缓冲区里面的数据发送出去
接收数据
c
/**
* @ingroup tcp_raw
* Sets the callback function that will be called when new data
* arrives. The callback function will be passed a NULL pbuf to
* indicate that the remote host has closed the connection. If the
* callback function returns ERR_OK or ERR_ABRT it must have
* freed the pbuf, otherwise it must not have freed it.
*
* @param pcb tcp_pcb to set the recv callback
* @param recv callback function to call for this pcb when data is received
*/
void
tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
设置接收数据的回调函数
c
/**
* @ingroup tcp_raw
* This function should be called by the application when it has
* processed the data. The purpose is to advertise a larger window
* when the data has been processed.
*
* @param pcb the tcp_pcb for which data is read
* @param len the amount of bytes that have been read by the application
*/
void
tcp_recved(struct tcp_pcb *pcb, u16_t len)
断开
c
/**
* @ingroup tcp_raw
* Closes the connection held by the PCB.
*
* Listening pcbs are freed and may not be referenced any more.
* Connection pcbs are freed if not yet connected and may not be referenced
* any more. If a connection is established (at least SYN received or in
* a closing state), the connection is closed, and put in a closing state.
* The pcb is then automatically freed in tcp_slowtmr(). It is therefore
* unsafe to reference it (unless an error is returned).
*
* The function may return ERR_MEM if no memory
* was available for closing the connection. If so, the application
* should wait and try again either by using the acknowledgment
* callback or the polling functionality. If the close succeeds, the
* function returns ERR_OK.
*
* @param pcb the tcp_pcb to close
* @return ERR_OK if connection has been closed
* another err_t if closing failed and pcb is not freed
*/
err_t tcp_close(struct tcp_pcb *pcb)
断开链接, 这一个pcb不再进行连接, 并释放已经进行的连接和这一个控制块, 用于监听pcb
c
/**
* @ingroup tcp_raw
* Aborts the connection by sending a RST (reset) segment to the remote
* host. The pcb is deallocated. This function never fails.
*
* ATTENTION: When calling this from one of the TCP callbacks, make
* sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
* or you will risk accessing deallocated memory or memory leaks!
*
* @param pcb the tcp pcb to abort
*/
void tcp_abort(struct tcp_pcb *pcb);
一个普通的pcb断开连接, 在回调函数里面调用的时候, 回调函数需要返回一个ERR_ABRT
使用
客户端
c
tcppcb = tcp_new(); /* 创建一个新的pcb */
if (tcppcb) /* 创建成功 */
{
IP4_ADDR(&rmtipaddr, g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]);
tcp_connect(tcppcb, &rmtipaddr, LWIP_DEMO_PORT, lwip_tcp_client_connected); /* 连接到目的地址的指定端口上,当连接成功后回调lwip_tcp_client_connected()函数 */
}
else res = 1;
使用这一个方式进行连接
- 连接回调函数
c
/**
* @brief lwIP TCP连接建立后调用回调函数
* @param arg : 回调函数传入的参数
* @param tpcb : TCP控制块
* @param err : 错误码
* @retval 返回错误码
*/
err_t lwip_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
struct tcp_client_struct *es = NULL;
if (err == ERR_OK)
{
es = (struct tcp_client_struct *)mem_malloc(sizeof(struct tcp_client_struct)); /* 申请内存 */
if (es) /* 内存申请成功 */
{
es->state = ES_TCPCLIENT_CONNECTED; /* 状态为连接成功 */
es->pcb = tpcb;
es->p = NULL;
tcp_arg(tpcb, es); /* 使用es更新tpcb的callback_arg */
tcp_recv(tpcb, lwip_tcp_client_recv); /* 初始化LwIP的tcp_recv回调功能 */
tcp_err(tpcb, lwip_tcp_client_error); /* 初始化tcp_err()回调函数 */
tcp_sent(tpcb, lwip_tcp_client_sent); /* 初始化LwIP的tcp_sent回调功能 */
tcp_poll(tpcb, lwip_tcp_client_poll, 1); /* 初始化LwIP的tcp_poll回调功能 */
g_lwip_send_flag |= 1 << 5; /* 标记连接到服务器了 */
err = ERR_OK;
}
else
{
lwip_tcp_client_connection_close(tpcb, es); /* 关闭连接 */
err = ERR_MEM; /* 返回内存分配错误 */
}
}
else
{
lwip_tcp_client_connection_close(tpcb, 0); /* 关闭连接 实际是设置回调函数为NULL*/
}
return err;
}
- 断开连接
c
/**
* @brief 关闭与服务器的连接
* @param tpcb: TCP控制块
* @param es : LWIP回调函数使用的结构体
* @retval 无
*/
void lwip_tcp_client_connection_close(struct tcp_pcb *tpcb, struct tcp_client_struct *es)
{
/* 移除回调 */
tcp_abort(tpcb); /* 终止连接,删除pcb控制块 */
tcp_arg(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
if (es)mem_free(es);
g_lwip_send_flag &= ~(1 << 5); /* 标记连接断开了 */
}
- 轮询函数
c
/**
* @brief lwIP tcp_poll的回调函数
* @param arg : 回调函数传入的参数
* @param tpcb: TCP控制块
* @retval ERR_OK
*/
err_t lwip_tcp_client_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_client_struct *es;
es = (struct tcp_client_struct *)arg;
if (es->state == ES_TCPCLIENT_CLOSING) /* 连接断开 */
{
lwip_tcp_client_connection_close(tpcb, es); /* 关闭TCP连接 */
}
ret_err = ERR_OK;
return ret_err;
}
循环的回调函数, 这一个函数会被循环调用
- 发送函数
c
/**
* @brief lwIP tcp_sent的回调函数(当从远端主机接收到ACK信号后发送数据)
* @param arg : 回调函数传入的参数
* @param tpcb: TCP控制块
* @param len : 长度
* @retval ERR_OK
*/
err_t lwip_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct tcp_client_struct *es;
LWIP_UNUSED_ARG(len);
es = (struct tcp_client_struct *)arg;
if (es->p)lwip_tcp_client_senddata(tpcb, es); /* 发送数据 */
return ERR_OK;
}
/**
* @brief 用来发送数据
* @param tpcb: TCP控制块
* @param es : LWIP回调函数使用的结构体
* @retval 无
*/
void lwip_tcp_client_senddata(struct tcp_pcb *tpcb, struct tcp_client_struct *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
while ((wr_err == ERR_OK) && es->p && (es->p->len <= tcp_sndbuf(tpcb))) /* 将要发送的数据加入到发送缓冲队列中 */
{
ptr = es->p;
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1); //把数据加入缓冲里面
if (wr_err == ERR_OK)
{
es->p = ptr->next; /* 指向下一个pbuf */
if (es->p)pbuf_ref(es->p); /* pbuf的ref加一 */
pbuf_free(ptr); /* 释放ptr */
}
else if (wr_err == ERR_MEM)es->p = ptr;
tcp_output(tpcb); /* 将发送缓冲队列中的数据立即发送出去 */
}
}
实际发送的时候, 可以直接调用lwip_tcp_client_senddata函数进行发送
- 接收函数
c
/**
* @brief lwIP tcp_recv()函数的回调函数
* @param arg : 回调函数传入的参数
* @param tpcb : TCP控制块
* @param p : 网络数据包
* @param err : 错误码
* @retval 返回错误码
*/
err_t lwip_tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
uint32_t data_len = 0;
struct pbuf *q;
struct tcp_client_struct *es;
err_t ret_err;
LWIP_ASSERT("arg != NULL", arg != NULL);
es = (struct tcp_client_struct *)arg;
if (p == NULL) /* 如果从服务器接收到空的数据帧就关闭连接 */
{
es->state = ES_TCPCLIENT_CLOSING; /* 需要关闭TCP 连接了 */
es->p = p;
ret_err = ERR_OK;
}
else if (err != ERR_OK) /* 当接收到一个非空的数据帧,但是err!=ERR_OK */
{
if (p)pbuf_free(p); /* 释放接收pbuf */
ret_err = err;
}
else if (es->state == ES_TCPCLIENT_CONNECTED) /* 当处于连接状态时 */
{
if (p != NULL) /* 当处于连接状态并且接收到的数据不为空时 */
{
memset(g_lwip_demo_recvbuf, 0, LWIP_DEMO_RX_BUFSIZE); /* 数据接收缓冲区清零 */
for (q = p; q != NULL; q = q->next) /* 遍历完整个pbuf链表 */
{
/* 判断要拷贝到LWIP_DEMO_RX_BUFSIZE中的数据是否大于LWIP_DEMO_RX_BUFSIZE的剩余空间,如果大于 */
/* 的话就只拷贝LWIP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据 */
if (q->len > (LWIP_DEMO_RX_BUFSIZE - data_len)) memcpy(g_lwip_demo_recvbuf + data_len, q->payload, (LWIP_DEMO_RX_BUFSIZE - data_len)); /* 拷贝数据 */
else memcpy(g_lwip_demo_recvbuf + data_len, q->payload, q->len);
data_len += q->len;
if (data_len > LWIP_DEMO_RX_BUFSIZE) break; /* 超出TCP客户端接收数组,跳出 */
}
g_lwip_send_flag |= 1 << 6; /* 标记接收到数据了 */
tcp_recved(tpcb, p->tot_len); /* 用于获取接收数据,通知LWIP可以获取更多数据 */
pbuf_free(p); /* 释放内存 */
ret_err = ERR_OK;
}
}
else /* 接收到数据但是连接已经关闭 */
{
tcp_recved(tpcb, p->tot_len); /* 用于获取接收数据,通知LWIP可以获取更多数据 */
es->p = NULL;
pbuf_free(p); /* 释放内存 */
ret_err = ERR_OK;
}
return ret_err;
}
服务器
c
tcppcbnew = tcp_new(); /* 创建一个新的pcb */
if (tcppcbnew) /* 创建成功 */
{
err = tcp_bind(tcppcbnew, IP_ADDR_ANY, LWIP_DEMO_PORT); /* 将本地IP与指定的端口号绑定在一起,IP_ADDR_ANY为绑定本地所有的IP地址 */
if (err == ERR_OK) /* 绑定完成 */
{
tcppcbconn = tcp_listen(tcppcbnew); /* 设置tcppcb进入监听状态 */
tcp_accept(tcppcbconn, lwip_tcp_server_accept); /* 初始化LWIP的tcp_accept的回调函数 */
}
else res = 1;
}
else res = 1;
c
/**
* @brief lwIP tcp_accept()的回调函数
* @param arg :传入的参数
* @param newpcb:TCP控制块
* @param err :错误码
* @retval 返回 ret_err
*/
err_t lwip_tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_server_struct *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
tcp_setprio(newpcb, TCP_PRIO_MIN); /* 设置新创建的pcb优先级 */
es = (struct tcp_server_struct *)mem_malloc(sizeof(struct tcp_server_struct)); /* 分配内存 */
if (es != NULL) /* 内存分配成功 */
{
es->state = ES_TCPSERVER_ACCEPTED; /* 接收连接 */
es->pcb = newpcb;
es->p = NULL;
tcp_arg(newpcb, es);
tcp_recv(newpcb, lwip_tcp_server_recv); /* 初始化tcp_recv()的回调函数 */
tcp_err(newpcb, lwip_tcp_server_error); /* 初始化tcp_err()回调函数 */
tcp_poll(newpcb, lwip_tcp_server_poll, 1); /* 初始化tcp_poll回调函数 */
tcp_sent(newpcb, lwip_tcp_server_sent); /* 初始化发送回调函数 */
g_lwip_send_flag |= 1 << 5; /* 标记有客户端连上了 */
g_lwipdev.remoteip[0] = newpcb->remote_ip.addr & 0xff; /* IADDR4 */
g_lwipdev.remoteip[1] = (newpcb->remote_ip.addr >> 8) & 0xff; /* IADDR3 */
g_lwipdev.remoteip[2] = (newpcb->remote_ip.addr >> 16) & 0xff; /* IADDR2 */
g_lwipdev.remoteip[3] = (newpcb->remote_ip.addr >> 24) & 0xff; /* IADDR1 */
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err;
}