LWIP之SOCKET的实现

这篇博客详细介绍了Lwip协议栈如何实现Socket接口,包括标准的socket函数如accept、bind等的宏定义,并深入到源码层面,探讨了 lwip_accept 函数、netconn 结构体和alloc_socket函数的工作原理,以及TCP连接的建立过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Lwip协议栈的实现目的,无非是要上层用来实现app的socket编程。好,我们就从socket开始。为了兼容性,lwip的socket应该也是提供标准的socket接口函数,恩,没错,在src\include\lwip\socket.h文件中可以看到下面的宏定义:
#if LWIP_COMPAT_SOCKETS
#define accept(a,b,c) lwip_accept(a,b,c)
#define bind(a,b,c) lwip_bind(a,b,c)
#define shutdown(a,b) lwip_shutdown(a,b)
#define closesocket(s) lwip_close(s)
#define connect(a,b,c) lwip_connect(a,b,c)
#define getsockname(a,b,c) lwip_getsockname(a,b,c)
#define getpeername(a,b,c) lwip_getpeername(a,b,c)
#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
#define listen(a,b) lwip_listen(a,b)
#define recv(a,b,c,d) lwip_recv(a,b,c,d)
#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
#define send(a,b,c,d) lwip_send(a,b,c,d)
#define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f)
#define socket(a,b,c) lwip_socket(a,b,c)
#define select(a,b,c,d,e) lwip_select(a,b,c,d,e)
#define ioctlsocket(a,b,c) lwip_ioctl(a,b,c)

#if LWIP_POSIX_SOCKETS_IO_NAMES
#define read(a,b,c) lwip_read(a,b,c)
#define write(a,b,c) lwip_write(a,b,c)
#define close(s) lwip_close(s)
先不说实际的实现函数,光看这些定义的宏,就是标准socket所必须有的接口。

接着看这些实际的函数实现。这些函数实现在src\api\socket.c中。先看下接受连接的函数,这个是tcp的
原型:int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
可以看到这里的socket类型参数 s,实际上是个int型
在这个函数中的第一个函数调用是sock = get_socket(s);
这里的sock变量类型是lwip_socket,定义如下:
/** Contains all internal pointers and states used for a socket */
struct lwip_socket {
/** sockets currently are built on netconns, each socket has one netconn */
struct netconn *conn;
/** data that was left from the previous read */
struct netbuf *lastdata;
/** offset in the data that was left from the previous read */
u16_t lastoffset;
/** number of times data was received, set by even
### LWIP Socket 的使用方法及示例代码 LWIP 是一种轻量级 TCP/IP 协议栈,广泛应用于嵌入式系统中。它提供了类似于 BSD Socket 的接口,使得开发者能够轻松实现网络通信功能[^1]。 #### 1. 创建套接字 (Socket) `lwip_socket()` 函数用于创建一个新的套接字描述符。此函数的第一个参数指定协议族(通常为 `AF_INET`),第二个参数指定套接字类型(如 `SOCK_STREAM` 表示 TCP 或 `SOCK_DGRAM` 表示 UDP),第三个参数指定具体的协议(通常是 `IPPROTO_TCP` 或 `IPPROTO_UDP`)。 ```c int sockfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { printf("Failed to create socket\n"); } ``` #### 2. 连接到远程服务器 (Connect) 对于 TCP 客户端而言,需要调用 `lwip_connect()` 来建立到目标服务器的连接。在此之前,需先填充目标地址结构体 `struct sockaddr_in`。 ```c struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(80); // 假设目标端口为80 server_addr.sin_addr.s_addr = inet_addr("192.168.1.1"); // 目标IP地址 if (lwip_connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0) { printf("Connection failed\n"); } ``` #### 3. 数据传输 (Read/Write) 一旦建立了连接,就可以通过 `lwip_read()` 和 `lwip_write()` 实现数据的读取和写入操作。 ```c // 发送数据 const char *message = "Hello Server"; if (lwip_write(sockfd, message, strlen(message)) <= 0) { printf("Send data failed\n"); } // 接收数据 char buffer[1024]; int bytes_received = lwip_read(sockfd, buffer, sizeof(buffer)-1); if (bytes_received > 0) { buffer[bytes_received] = '\0'; printf("Received: %s\n", buffer); } else { printf("Receive data failed or connection closed\n"); } ``` #### 4. 关闭套接字 (Close) 完成通信后,应关闭套接字以释放资源。 ```c lwip_close(sockfd); ``` --- 以下是完整的 TCP 客户端示例代码: ```c #include "lwip/api.h" #include "lwip/netdb.h" void tcp_client_example() { int sockfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { printf("Failed to create socket\n"); return; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(80); // 设置目标端口 server_addr.sin_addr.s_addr = inet_addr("192.168.1.1"); // 设置目标IP地址 if (lwip_connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0) { printf("Connection failed\n"); lwip_close(sockfd); return; } const char *message = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; // 示例HTTP请求 if (lwip_write(sockfd, message, strlen(message)) <= 0) { printf("Send data failed\n"); } else { char buffer[1024]; int bytes_received = lwip_read(sockfd, buffer, sizeof(buffer)-1); if (bytes_received > 0) { buffer[bytes_received] = '\0'; printf("Response from server:\n%s\n", buffer); } } lwip_close(sockfd); } ``` 上述代码展示了一个简单的 TCP 客户端实例,其中涉及了套接字的创建、连接、数据交互以及关闭过程[^3]。 --- UDP 的使用方式与此类似,但无需显式的连接阶段。可以直接调用 `lwip_sendto()` 将数据发送至特定的目标地址,并通过 `lwip_recvfrom()` 获取来自任意源的数据包[^4]。 --- #### 注意事项 - 在实际项目中,务必处理可能发生的错误情况并加入超时机制。 - 对于 STM32 平台上的具体实现细节,请参考相关文档或示例代码[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值