LWIP的Socket接口

Socket接口简介

类似于文件操作的一种网络连接接口,通常将其称之为“套接字”。lwIPSocket接口兼容BSD Socket接口,但只实现完整Socket的部分功能

netconn是对RAW的封装

Socket是对netconn的封装

SOCKET结构体

struct sockaddr {
u8_t sa_len; /* 长度 */
sa_family_t sa_family; /* 协议簇 */
char sa_data[14]; /* 连续的 14 字节信息 */
};
struct sockaddr_in {
u8_t sin_len; /* 长度 */
u8_t sin_family; /* 协议簇 */
u16_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP 地址 */
char sin_zero[8];
}

为啥用两个结构体

sockaddr的缺陷是:sa_zero把目标地址和端口信息混在了一起

sockaddr_in该结构体解决了sockaddr的缺陷,把port和addr分开存储在两个变量中

NETCONN相关函数

SOCKET API

描述

scoket

创建一个scoket连接

bind

服务器端绑定套接字与网卡信息

connect

Socket 与远程 IP 地址和端口号绑定

listen

监听连接

accept

断开连接

read/recv/recvfrom

监听连接(只在TCP服务器)

sendto/send/write

获取一个TCP连接(只在TCP服务器)

close

关闭连接

Socket 编程 UDP 连接流程
 

实现 UDP 协议之前, 用户必须先配置结构体 sockaddr_in 的成员变量才能实现 UDP 连接,该配置步骤如下所示:

① sin_family 设置为 AF_INET 表示 IPv4 网络协议。

② sin_port 为设置端口号, 笔者设置为 8080。

③ sin_addr.s_addr 设置本地 IP 地址。

④ 调用函数 Socket 创建 Socket 连接,注意: 该函数的第二个参数 SOCK_STREAM 表

示 TCP 连接, SOCK_DGRAM 表示 UDP 连接。

⑤ 调用函数 bind 将本地服务器地址与 Socket 进行绑定。

⑥ 调用收发函数接收或者发送。

实现连接的主要函数


/* 需要自己设置远程IP地址 */
#define IP_ADDR   "192.168.1.111"#define LWIP_DEMO_RX_BUFSIZE         200    /* 最大接收数据长度 */
#define LWIP_DEMO_PORT               8080   /* 连接的本地端口号 */
#define LWIP_SEND_THREAD_PRIO       ( tskIDLE_PRIORITY + 3 ) /* 发送数据线程优先级 *//* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE]; 
/* 发送数据内容 */
char g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 数据发送标志位 */
uint8_t g_lwip_send_flag;
struct sockaddr_in g_local_info;              /* 定义Socket地址信息结构体 */
socklen_t g_sock_fd;                          /* 定义一个Socket接口 */
static void lwip_send_thread(void *arg);extern QueueHandle_t g_display_queue;         /* 显示消息队列句柄 *//*** @brief       发送数据线程* @param       无* @retval      无*/
void lwip_data_send(void)
{sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO );
}/*** @brief       lwip_demo实验入口* @param       无* @retval      无*/
void lwip_demo(void)
{BaseType_t lwip_err;char *tbuf;lwip_data_send();                                   /* 创建发送数据线程 */memset(&g_local_info, 0, sizeof(struct sockaddr_in)); /* 将服务器地址清空 */g_local_info.sin_len = sizeof(g_local_info);g_local_info.sin_family = AF_INET;                    /* IPv4地址 */g_local_info.sin_port = htons(LWIP_DEMO_PORT);        /* 设置端口号 */g_local_info.sin_addr.s_addr = htons(INADDR_ANY);     /* 设置本地IP地址 */g_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);           /* 建立一个新的socket连接 */tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */lcd_show_string(5, 150, 200, 16, 16, tbuf, BLUE);/* 建立绑定 */bind(g_sock_fd, (struct sockaddr *)&g_local_info, sizeof(struct sockaddr_in));while (1){memset(g_lwip_demo_recvbuf, 0, sizeof(g_lwip_demo_recvbuf));recv(g_sock_fd, (void *)g_lwip_demo_recvbuf, sizeof(g_lwip_demo_recvbuf), 0);lwip_err = xQueueSend(g_display_queue,&g_lwip_demo_recvbuf,0);if (lwip_err == errQUEUE_FULL){printf("队列Key_Queue已满,数据发送失败!\r\n");}}
}/*** @brief       发送数据线程函数* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void lwip_send_thread(void *pvParameters)
{pvParameters = pvParameters;g_local_info.sin_addr.s_addr = inet_addr(IP_ADDR);                /* 需要发送的远程IP地址 */while (1){if ((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA)     /* 有数据要发送 */{sendto(g_sock_fd,                                         /* scoket */(char *)g_lwip_demo_sendbuf,                        /* 发送的数据 */sizeof(g_lwip_demo_sendbuf), 0,                     /* 发送的数据大小 */(struct sockaddr *)&g_local_info,                   /* 接收端地址信息 */ sizeof(g_local_info));                              /* 接收端地址信息大小 */g_lwip_send_flag &= ~LWIP_SEND_DATA;}vTaskDelay(100);}
}

Socket 编程 UDP 组播实验

必须对以下保证设置

\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_eth.c

static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err)

  macinit.ReceiveAll = ETH_RECEIVEALL_ENABLE;  //使能 全部接收

 macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_NONE;//不过滤 组播的帧

\Middlewares\lwip\arch\lwipopts.h

保证设置1

\Middlewares\LWIP\arch\ethernetif.c

static void low_level_init(struct netif *netif)

必须保证添加如下所有标志位

netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP|NETIF_FLAG_IGMP;   /*广播 ARP协议 链接检测*/

组播的主要实现函数

/* socket信息 */
struct link_socjet_info
{struct sockaddr_in client_addr; /* 网络地址信息 */socklen_t client_addr_len;      /* 网络地址信息长度 */int optval;                     /* 为存放选项值 */int sfd;                        /* socket控制块 */ip_mreq multicast_mreq;         /* 组播控制块 */struct{uint8_t *buf;               /* 缓冲空间 */uint32_t size;              /* 缓冲空间大小 */} send;                         /* 发送缓冲 */struct{uint8_t *buf;               /* 缓冲空间 */uint32_t size;              /* 缓冲空间大小 */} recv;                         /* 接收缓冲 */
};/* 多播信息 */
struct ip_mreq_t
{struct ip_mreq mreq;            /* 多播信息控制块 */socklen_t mreq_len;             /* 多播信息长度 */
};#define LWIP_SEND_THREAD_PRIO       (tskIDLE_PRIORITY + 3) /* 发送数据线程优先级 */
void lwip_send_thread(void *pvParameters);
/* 接收数据缓冲区 */
static uint8_t g_lwip_demo_recvbuf[1024];
static uint8_t g_lwip_demo_sendbuf[] = {"ALIENTEK DATA\r\n"}; /* 多播 IP 地址 */
#define GROUP_IP "224.0.1.0"/*** @brief       测试代码* @param       无* @retval      无*/
void lwip_demo(void)
{struct link_socjet_info *socket_info;struct ip_mreq_t *mreq_info;socket_info = mem_malloc(sizeof(struct link_socjet_info));mreq_info = mem_malloc(sizeof(struct ip_mreq_t));socket_info->sfd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_info->sfd < 0){printf("socket failed!\n");}socket_info->client_addr.sin_family = AF_INET;socket_info->client_addr.sin_addr.s_addr = htonl(INADDR_ANY);   /* 待与 socket 绑定的本地网络接口 IP */   socket_info->client_addr.sin_port = htons(9999);                /* 待与 socket 绑定的本地端口号 */socket_info->client_addr_len = sizeof(socket_info->client_addr);/* 设置接收和发送缓冲区 */socket_info->recv.buf = g_lwip_demo_recvbuf;socket_info->recv.size = sizeof(g_lwip_demo_recvbuf);socket_info->send.buf = g_lwip_demo_sendbuf;socket_info->send.size = sizeof(g_lwip_demo_sendbuf);/* 将 Socket 与本地某网络接口绑定 */int ret = bind(socket_info->sfd, (struct sockaddr*)&socket_info->client_addr, socket_info->client_addr_len);if (ret < 0){printf(" bind error!\n ");}mreq_info->mreq.imr_multiaddr.s_addr = inet_addr(GROUP_IP);     /* 多播组 IP 地址设置 */mreq_info->mreq.imr_interface.s_addr = htonl(INADDR_ANY);       /* 待加入多播组的 IP 地址 */mreq_info->mreq_len = sizeof(struct ip_mreq);/* 添加多播组成员(该语句之前,socket 只与 某单播IP地址相关联 执行该语句后 将与多播地址相关联) */ret = setsockopt(socket_info->sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq_info->mreq,mreq_info->mreq_len);if (ret < 0){printf("setsockopt failed !");}else{printf("setsockopt success\n");}int length = 0;struct sockaddr_in sender;int sender_len = sizeof(sender);sys_thread_new("lwip_send_thread", lwip_send_thread, (void *)socket_info, 512, LWIP_SEND_THREAD_PRIO );while(1){length = recvfrom(socket_info->sfd,socket_info->recv.buf,socket_info->recv.size,0,(struct sockaddr*)&sender,(socklen_t *)&sender_len);socket_info->recv.buf[length]='\0';printf("%s %d : %s\n", inet_ntoa(sender.sin_addr), ntohs(sender.sin_port), socket_info->recv.buf);vTaskDelay(10);}setsockopt(socket_info->sfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq_info->mreq, mreq_info->mreq_len);closesocket(socket_info->sfd);
}/*** @brief       发送数据线程函数* @param       pvParameters : 传入struct link_socjet_info结构体* @retval      无*/
void lwip_send_thread(void *pvParameters)
{struct link_socjet_info *socket_info = pvParameters;socket_info->client_addr.sin_addr.s_addr = inet_addr(GROUP_IP); /* 组播ip */while (1){/* 数据广播 */sendto(socket_info->sfd, socket_info->send.buf, socket_info->send.size + 1, 0, (struct sockaddr*)&socket_info->client_addr,socket_info->client_addr_len);vTaskDelay(1000);}
}

Socket 编程 TCP 客户端流程
 

实现 TCP 客户端之前,用户必须先配置结构体 sockaddr_in 的成员变量才能实现TCPClient 连接,该配置步骤如下所示:

① sin_family 设置为 AF_INET 表示 IPv4 网络协议。

② sin_port 为设置端口号。

③ sin_addr.s_addr 设置远程 IP 地址。

④ 调用函数 Socket 创建 Socket 连接, 注意: 该函数的第二个参数 SOCK_STREAM 表

示 TCP 连接, SOCK_DGRAM 表示 UDP 连接。

⑤ 调用函数 connect 连接远程 IP 地址。

⑥ 调用收发函数实现远程通讯。

Socket 接口的 TCPClient 实验
 

实现的主要代码

/* 设置远程IP地址 */
//#define DEST_IP_ADDR0               192
//#define DEST_IP_ADDR1               168
//#define DEST_IP_ADDR2                 1
//#define DEST_IP_ADDR3               167/* 需要自己设置远程IP地址 */
#define IP_ADDR   "192.168.1.37"#define LWIP_DEMO_RX_BUFSIZE         100                        /* 最大接收数据长度 */
#define LWIP_DEMO_PORT               8080                       /* 连接的本地端口号 */
#define LWIP_SEND_THREAD_PRIO       ( tskIDLE_PRIORITY + 3 )    /* 发送数据线程优先级 */
/* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE]; /* 发送数据内容 */
uint8_t g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 数据发送标志位 */
uint8_t g_lwip_send_flag;
int g_sock = -1;
int g_lwip_connect_state = 0;
static void lwip_send_thread(void *arg);extern QueueHandle_t g_display_queue;     /* 显示消息队列句柄 *//*** @brief       发送数据线程* @param       无* @retval      无*/
void lwip_data_send(void)
{sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO );
}/*** @brief       lwip_demo实验入口* @param       无* @retval      无*/
void lwip_demo(void)
{struct sockaddr_in atk_client_addr;err_t err;int recv_data_len;BaseType_t lwip_err;char *tbuf;lwip_data_send();                                           /* 创建发送数据线程 */while (1){
sock_start:g_lwip_connect_state = 0;atk_client_addr.sin_family = AF_INET;                   /* 表示IPv4网络协议 */atk_client_addr.sin_port = htons(LWIP_DEMO_PORT);       /* 端口号 */atk_client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);   /* 远程IP地址 */g_sock = socket(AF_INET, SOCK_STREAM, 0);                 /* 可靠数据流交付服务既是TCP协议 */memset(&(atk_client_addr.sin_zero), 0, sizeof(atk_client_addr.sin_zero));tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */lcd_show_string(5, 150, 200, 16, 16, tbuf, BLUE);/* 连接远程IP地址 */err = connect(g_sock, (struct sockaddr *)&atk_client_addr, sizeof(struct sockaddr));if (err == -1){printf("连接失败\r\n");g_sock = -1;closesocket(g_sock);myfree(SRAMIN, tbuf);vTaskDelay(10);goto sock_start;}printf("连接成功\r\n");lcd_show_string(5, 90, 200, 16, 16, "State:Connection Successful", BLUE);g_lwip_connect_state = 1;while (1){recv_data_len = recv(g_sock,g_lwip_demo_recvbuf,LWIP_DEMO_RX_BUFSIZE,0);if (recv_data_len <= 0 ){closesocket(g_sock);g_sock = -1;lcd_fill(5, 89, lcddev.width,110, WHITE);lcd_show_string(5, 90, 200, 16, 16, "State:Disconnect", BLUE);myfree(SRAMIN, tbuf);goto sock_start;}/* 接收的数据 */ lwip_err = xQueueSend(g_display_queue,&g_lwip_demo_recvbuf,0);if (lwip_err == errQUEUE_FULL){printf("队列Key_Queue已满,数据发送失败!\r\n");}vTaskDelay(10);}}
}/*** @brief       发送数据线程函数* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void lwip_send_thread(void *pvParameters)
{pvParameters = pvParameters;err_t err;while (1){while (1){if(((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) && (g_lwip_connect_state == 1)) /* 有数据要发送 */{err = write(g_sock, g_lwip_demo_sendbuf, sizeof(g_lwip_demo_sendbuf));if (err < 0){break;}g_lwip_send_flag &= ~LWIP_SEND_DATA;}vTaskDelay(10);}closesocket(g_sock);}
}

Socket 编程 TCP 服务器流程
 

实现 TCP 服务器之前,用户必须先配置结构体 sockaddr_in 的成员变量才能实现TCPServer 连接,该配置步骤如下所示:

① sin_family 设置为 AF_INET 表示 IPv4 网络协议。

② sin_port 为设置端口号。

③ sin_addr.s_addr 设置本地 IP 地址。

④ 调用函数 Socket 创建 Socket 连接,注意:该函数的第二个参数 SOCK_STREAM

示 TCP 连接, SOCK_DGRAM 表示 UDP 连接。

⑤ 调用函数 bind 绑定本地 IP 地址和端口号。

⑥ 调用函数 listen 监听连接请求。

⑦ 调用函数 accept 监听连接。

⑧ 调用收发函数进行通讯。

上述的步骤就是 Socket 编程接口配置 TCPServer 的流程。

Socket 接口的 TCPServer 实验
 

之后应用不要什么goto代码


/* 设置远程IP地址 */
//#define DEST_IP_ADDR0               192
//#define DEST_IP_ADDR1               168
//#define DEST_IP_ADDR2                 1
//#define DEST_IP_ADDR3               167/* 需要自己设置远程IP地址 */
//#define IP_ADDR   "192.168.1.167"#define LWIP_DEMO_RX_BUFSIZE         200                        /* 最大接收数据长度 */
#define LWIP_DEMO_PORT               8080                       /* 连接的本地端口号 */
#define LWIP_SEND_THREAD_PRIO       ( tskIDLE_PRIORITY + 3 )    /* 发送数据线程优先级 *//* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE]; 
/* 发送数据内容 */
uint8_t g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";/* 数据发送标志位 */
uint8_t g_lwip_send_flag;
int g_sock_conn;                          /* 请求的 socked */
int g_lwip_connect_state = 0;
static void lwip_send_thread(void *arg);
extern QueueHandle_t g_display_queue;     /* 显示消息队列句柄 *//*** @brief       发送数据线程* @param       无* @retval      无*/
void lwip_data_send(void)
{sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO );
}/*** @brief       lwip_demo实验入口* @param       无* @retval      无*/
void lwip_demo(void)
{struct sockaddr_in server_addr; /* 服务器地址 */struct sockaddr_in conn_addr;   /* 连接地址 */socklen_t addr_len;             /* 地址长度 */int err;int length;int sock_fd;char *tbuf;BaseType_t lwip_err;lwip_data_send();                                    /* 创建一个发送线程 */sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* 建立一个新的socket连接 */memset(&server_addr, 0, sizeof(server_addr));        /* 将服务器地址清空 */server_addr.sin_family = AF_INET;                    /* 地址家族 */server_addr.sin_addr.s_addr = htonl(INADDR_ANY);     /* 注意转化为网络字节序 */server_addr.sin_port = htons(LWIP_DEMO_PORT);        /* 使用SERVER_PORT指定为程序头设定的端口号 */tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */lcd_show_string(5, 150, 200, 16, 16, tbuf, BLUE);err = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); /* 建立绑定 */if (err < 0)                /* 如果绑定失败则关闭套接字 */{closesocket(sock_fd);   /* 关闭套接字 */myfree(SRAMIN, tbuf);}err = listen(sock_fd, 4);   /* 监听连接请求 */if (err < 0)                /* 如果监听失败则关闭套接字 */{closesocket(sock_fd);   /* 关闭套接字 */}while(1){g_lwip_connect_state = 0;addr_len = sizeof(struct sockaddr_in); /* 将链接地址赋值给addr_len */g_sock_conn = accept(sock_fd, (struct sockaddr *)&conn_addr, &addr_len); /* 对监听到的请求进行连接,状态赋值给sock_conn */if (g_sock_conn < 0) /* 状态小于0代表连接故障,此时关闭套接字 */{closesocket(sock_fd);}else {lcd_show_string(5, 90, 200, 16, 16, "State:Connection Successful", BLUE);g_lwip_connect_state = 1;}while (1){memset(g_lwip_demo_recvbuf,0,LWIP_DEMO_RX_BUFSIZE);length = recv(g_sock_conn, (unsigned int *)g_lwip_demo_recvbuf, sizeof(g_lwip_demo_recvbuf), 0); /* 将收到的数据放到接收Buff */if (length <= 0){goto atk_exit;}//            printf("%s",g_lwip_demo_recvbuf);lwip_err = xQueueSend(g_display_queue,&g_lwip_demo_recvbuf,0);if (lwip_err == errQUEUE_FULL){printf("队列Key_Queue已满,数据发送失败!\r\n");}}
atk_exit:if (g_sock_conn >= 0){          closesocket(g_sock_conn);g_sock_conn = -1;lcd_fill(5, 89, lcddev.width,110, WHITE);lcd_show_string(5, 90, 200, 16, 16, "State:Disconnect", BLUE);myfree(SRAMIN, tbuf);}}
}/*** @brief       发送数据线程函数* @param       pvParameters : 传入参数(未用到)* @retval      无*/
static void lwip_send_thread(void *pvParameters)
{pvParameters = pvParameters;while (1){if(((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) && (g_lwip_connect_state == 1)) /* 有数据要发送 */{send(g_sock_conn, g_lwip_demo_sendbuf, sizeof(g_lwip_demo_sendbuf), 0); /* 发送数据 */g_lwip_send_flag &= ~LWIP_SEND_DATA;}vTaskDelay(1);}
}

Socket 编程接口 TCP 服务器多连接实验

开发板作为服务器,让多个客户端连接

客户端信息的结构体

/* 客户端的信息 */
struct client_info
{int socket_num;                 /* socket号的数量 */struct sockaddr_in ip_addr;     /* socket客户端的IP地址 */int sockaddr_len;               /* socketaddr的长度 */
};

客户端的任务信息结构体

/* 客户端的任务信息 */
struct client_task_info
{UBaseType_t client_task_pro;    /* 客户端任务优先级 */uint16_t client_task_stk;       /* 客户端任务优先级 */TaskHandle_t * client_handler;  /* 客户端任务控制块 */char *client_name;              /* 客户端任务名称 */char *client_num;               /* 客户端任务数量 */
};

socket信息结构体

/* socket信息 */
struct link_socjet_info
{int sock_listen;                /* 监听 */int sock_connect;               /* 连接 */struct sockaddr_in listen_addr; /* 监听地址 */struct sockaddr_in connect_addr;/* 连接地址 */
};

实现多链接的主要函数


/*** @brief       客户端的任务函数* @param       pvParameters : 传入链接客户端的信息* @retval      无*/
void lwip_client_thread_entry(void *param)
{struct client_info* client = param;/* 某个客户端连接 */printf("Client[%d]%s:%d is connect server\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port));/* 向客户端发送连接成功信息 */send(client->socket_num, (const void* )send_data, strlen(send_data), 0);while (1){char str[2048];memset(str, 0, sizeof(str));int bytes = recv(client->socket_num, str, sizeof(str), 0);//客户端发来的数据/* 获取关闭连接的请求 */if (bytes <= 0){mem_free(client);closesocket(client->socket_num);break;//退出这个whiel 删除任务}printf("[%d]%s:%d=>%s...\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port), str);send((int )client->socket_num, (const void * )str, (size_t )strlen(str), 0);}printf("[%d]%s:%d is disconnect...\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port));vTaskDelete(NULL); /* 删除该任务 */
}/*** @brief       lwip_demo实验入口* @param       无* @retval      无*/
void lwip_demo(void)
{struct client_info *client_fo;struct client_task_info *client_task_fo;struct link_socjet_info *socket_link_info;int sin_size = sizeof(struct sockaddr_in);char client_name[10] = "cli";char client_num[10];/* socket连接结构体申请内存 */socket_link_info = mem_malloc(sizeof(struct link_socjet_info));/* 设置客户端任务信息 */client_task_fo = mem_malloc(sizeof(struct client_task_info));client_task_fo->client_handler = NULL;client_task_fo->client_task_pro = 5;client_task_fo->client_task_stk = 512;/* 创建socket连接 */if ((socket_link_info->sock_listen = socket(AF_INET, SOCK_STREAM, 0)) == -1){printf("Socket error\r\n");return;}/* 初始化连接的服务端地址 *///记录每个客户端的ip地址socket_link_info->listen_addr.sin_family = AF_INET;socket_link_info->listen_addr.sin_port = htons(8088);socket_link_info->listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);memset(&(socket_link_info->listen_addr.sin_zero), 0, sizeof(socket_link_info->listen_addr.sin_zero));/* 绑定socket和连接的服务端地址信息 */if (bind(socket_link_info->sock_listen, (struct sockaddr * )&socket_link_info->listen_addr, sizeof(struct sockaddr)) < 0){printf("Bind fail!\r\n");goto __exit;}/* 监听客户端的数量 */listen(socket_link_info->sock_listen, 4);printf("begin listing...\r\n");while (1){/* 请求客户端连接 */socket_link_info->sock_connect = accept(socket_link_info->sock_listen, (struct sockaddr* )&socket_link_info->connect_addr, (socklen_t* )&sin_size);if (socket_link_info->sock_connect == -1){printf("no socket,waitting others socket disconnect.\r\n");continue;}lwip_itoa((char *)socket_link_info->sock_connect, (size_t)client_num, 10);strcat(client_name, client_num);client_task_fo->client_name = client_name;client_task_fo->client_num = client_num;/* 初始化连接客户端信息 */client_fo = mem_malloc(sizeof(struct client_info));client_fo->socket_num = socket_link_info->sock_connect;memcpy(&client_fo->ip_addr, &socket_link_info->connect_addr, sizeof(struct sockaddr_in));client_fo->sockaddr_len = sin_size;/* 创建连接的客户端任务 */xTaskCreate((TaskFunction_t )lwip_client_thread_entry,(const char *   )client_task_fo->client_name,(uint16_t       )client_task_fo->client_task_stk,(void *         )(void*) client_fo,(UBaseType_t    )client_task_fo->client_task_pro ++ ,(TaskHandle_t * )&client_task_fo->client_handler);if (client_task_fo->client_handler == NULL){printf("no memery for thread %s startup failed!\r\n",client_task_fo->client_name);mem_free(client_fo);continue;}else{printf("thread %s success!\r\n", client_task_fo->client_name);}}__exit: printf("listener failed\r\n");/* 关闭这个socket */closesocket(socket_link_info->sock_listen);vTaskDelete(NULL); /* 删除本任务 */
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/83631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows 安装gdal实现png转tif,以及栅格拼接

windows 安装gdal实现png转tif&#xff0c;以及栅格拼接 一、安装gdal 网上有很多安装gdal的方法&#xff0c;此处通过osgeo4w安装gdal 1.下载osgeo4w 下载地址 https://trac.osgeo.org/osgeo4w/ 2、安装osgeo4w exe文件安装&#xff0c;前面部分很简单&#xff0c;就不再…

Node.js 源码概览

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;它的源码结构相当庞大且复杂。下面我将为你讲解 Node.js 源码的主要结构和关键组成部分。 源码结构 Node.js 的主要源码目录结构如下&#xff1a; node/ ├── lib/ # JavaScript 核心模…

Linux :线程 【生产者消费者模型】

Linux &#xff1a;线程 【生产者消费者模型与信号量】 &#xff08;一&#xff09;生产消费模型1、生产消费模式概念2、生产者消费者之间的关系3、生产者消费者模型优点 &#xff08;二&#xff09;基于BlockingQueue的生产者消费者模型1、基于阻塞队列模型2、模拟实现基于阻塞…

mac本地docker镜像上传指定虚拟机

在Mac本地将Docker镜像上传至指定虚拟机的完整步骤 1. 在Mac本地保存Docker镜像为文件 通过docker save命令将镜像打包为.tar文件&#xff0c;便于传输至虚拟机。 # 示例&#xff1a;保存名为"my_image"的镜像到当前目录 docker save -o my_image.tar my_image:ta…

C++跨平台开发经验与解决方案

在当今软件开发领域&#xff0c;跨平台开发已成为一个重要的需求。C作为一种强大的系统级编程语言&#xff0c;在跨平台开发中扮演着重要角色。本文将分享在实际项目中的跨平台开发经验和解决方案。 1. 构建系统选择 CMake的优势 跨平台兼容性好 支持多种编译器和IDE 强大…

Void: Cursor 的开源平替

GitHub&#xff1a;https://github.com/voideditor/void 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Void&#xff0c;这款编辑器号称是开源的 Cursor 和 GitHub Copilot 替代品&#xff0c;而且完全免费&#xff01; 在你的代码库…

基于HTML+JavaScript+CSS实现教学网站

摘要 21世纪是信息化的时代&#xff0c;信息化物品不断地涌入我们的生活。同时&#xff0c;教育行业也产生了重大变革。传统的身心教授的模式&#xff0c;正在被替代。互联网模式的教育开辟了一片新的热土。 这算是对教育行业的一次重大挑战。截至目前&#xff0c;众多教育行…

基于ssm+mysql的高校设备管理系统(含LW+PPT+源码+系统演示视频+安装说明)

系统功能 管理员功能&#xff1a;系统登录、员工管理、设备管理、设备采购统计、设备报废统计&#xff1b;用户角色功能&#xff1a;设备采购管理、设备报废管理、个人资料管理。 作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vu…

电力杆塔安全监测解决方案

一、方案背景 在台风、滑坡等自然灾害出现时&#xff0c;极易产生倒杆、断杆、杆塔倾斜、塔基滑动等致使杆塔失稳的状况&#xff0c;进而引发导线断线、线路跳闸等事故&#xff0c;给电网的安全稳定运行造成影响。可借助在铁塔上装设的传感器&#xff0c;能够感知铁塔的工作状态…

基于Quicker构建从截图到公网图像链接获取的自动化流程

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言预备内容转webp程序PicGo设置Quicker设置视频演示总结互动致谢参考 前言 在自建博…

Python Requests库完全指南:从入门到精通

引言 在Python的生态系统中&#xff0c;requests库以其简洁优雅的API设计和强大的功能&#xff0c;成为HTTP请求处理领域的标杆工具。无论是数据爬虫开发、API接口调用&#xff0c;还是自动化测试场景&#xff0c;requests都能将复杂的网络交互简化为几行可读性极高的代码。相…

渗透测试核心技术:内网渗透与横向移动

内网渗透是红队行动的关键阶段,攻击者通过突破边界进入内网后,需快速定位域控、横向移动并维持权限。本节从内网环境搭建、信息收集、横向移动技巧到权限维持工具,系统讲解如何在内网中隐蔽行动并扩大战果。 1. 内网环境搭建与基础配置 目标: 模拟真实企业网络,构建包含…

学习FineBI

FineBI 第一章 FineBI 介绍 1.1. FineBI 概述 FineBI 是帆软软件有限公司推出的一款商业智能 &#xff08;Business Intelligence&#xff09; 产品 。 FineBI 是新一代大数据分析的 BI 工具 &#xff0c; 旨在帮助企业的业务人员充分了解和利用他们的数据 。FineBI 凭借强…

CSS 浮动(Float)及其应用

1. 什么是浮动&#xff08;Float&#xff09;&#xff1f; 浮动元素会脱离正常的文档流&#xff08;Document Flow&#xff09;&#xff0c;并向左或向右移动&#xff0c;直到碰到父元素的边缘或另一个浮动元素。 基本语法 .float-left {float: left; }.float-right {float:…

二分算法的介绍简单易懂

目录 1.概论 2.朴素的二分算法 3.求左端点的二分算法和求右端点的二分算法 4.总结 1.概论 要想了解什么是二分算法&#xff0c;我们就要知道什么是二分算法&#xff0c;二分算法是根据数组的规律&#xff0c;每次查找的数据原来的效率可能要O&#xff08;n&#xff09;,而我…

ROS2学习(3)------架构概述

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 ROS版本&#xff1a;2 ROS 2&#xff08;Robot Operating System 2&#xff09;的设计旨在提供一个灵活、可扩展且高效的框架&#xff0c;用于编写复杂的机器人软件。它引入了发布者/订阅者&…

墨水屏显示模拟器程序解读

程序如下&#xff1a;出处https://github.com/tsl0922/EPD-nRF5?tabreadme-ov-file // GUI emulator for Windows // This code is a simple Windows GUI application that emulates the display of an e-paper device. #include <windows.h> #include <stdint.h>…

【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer

【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer spring-kafka官方文档: https://docs.spring.io/spring-kafka/docs/2.8.10/reference/pdf/spring-kafka-reference.pdf KafkaTemplate API: https://docs.spring.io/spring-kafka/api/org/springframe…

【言语理解】逻辑填空之逻辑对应11

front&#xff1a;词义辨析 11.1前后解释对应 填空的词汇大意可能是吖要结合实际情况不要一味高估导致适得其反的结果 未雨绸缪&#xff1a;趁着天没下雨&#xff0c;先修缮房屋门窗。比喻事先做好准备工作&#xff0c;预防意外的事发生。&#xff08;提前做好准备&#xff0c…

ubuntu上 opencv + eclipse + C++

ubuntu上 opencv eclipse C 1. 安装eclipse 安装eclipse不用说了&#xff0c;前置条件要安装java 配置快捷键方式 2. 新建c项目 配置opencv环境 project -> properties: 配置c标准库版本&#xff1a; 配置opencv头文件&#xff1a; 配置opencv库文件&#xff1a;…