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
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83631.shtml
英文地址,請注明出處:http://en.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;…