服務端:
1 //tcp_server_demo.h 2 3 #ifndef __TCP_SERVER_DEMO_H 4 #define __TCP_SERVER_DEMO_H 5 #include "sys.h" 6 #include "includes.h" 7 8 9 #define TCP_SERVER_RX_BUFSIZE 1460 //定義tcp server最大接收數據長度 10 #define TCP_SERVER_PORT 8087 //定義tcp server的端口 11 #define LWIP_SEND_DATA 0X80 //定義有數據發送 12 13 extern u8 tcp_server_recvbuf[TCP_SERVER_RX_BUFSIZE]; //TCP客戶端接收數據緩沖區 14 extern u8 tcp_server_flag; //TCP服務器數據發送標志位 15 extern u8 recflag; 16 17 INT8U tcp_server_init(void); //TCP服務器初始化(創建TCP服務器線程) 18 #endif
1 //tcp_server_demo.c 2 3 #include "tcp_server_demo.h" 4 #include "lwip/opt.h" 5 #include "lwip_comm.h" 6 #include "led.h" 7 #include "lwip/lwip_sys.h" 8 #include "lwip/api.h" 9 #include "lcd.h" 10 #include "malloc.h" 11 #include "recorder.h" 12 13 u8 tcp_server_recvbuf[TCP_SERVER_RX_BUFSIZE]; //TCP客戶端接收數據緩沖區 14 u8 *tcp_server_sendbuf; 15 u8 recflag=0; 16 17 18 u8 receive_flag = 0; 19 20 21 22 //TCP客戶端任務 任務優先級最高! 23 #define TCPSERVER_PRIO 6 24 //任務堆棧大小 25 #define TCPSERVER_STK_SIZE 300 26 //任務堆棧 27 OS_STK TCPSERVER_TASK_STK[TCPSERVER_STK_SIZE]; 28 29 30 31 /*服務器線程任務*/ 32 void my_tcp_server_thread(void *arg) 33 { 34 OS_CPU_SR cpu_sr; 35 36 struct pbuf *q; //創建pbuf 數據包 用於接收數據 37 u32 data_len = 0; //已經儲存的數據長度 38 err_t err,recv_err; //創建異常標志 39 u8 remot_addr[4]; //創建一個客戶機IP存儲數組 40 struct netconn *conn, *newconn; //netconn任務塊 LWIP會根據TCP還是UDP自動分配合適的消息郵箱 41 static ip_addr_t ipaddr; //創建一個存取ip地址的結構體 42 static u16_t port; //端口號 43 u8 i; 44 u8 re=0; 45 tcp_server_sendbuf=mymalloc(SRAMEX,SAI_RX_DMA_BUF_SIZE); 46 47 for(i=0;i<SAI_RX_FIFO_SIZE;i++) 48 { 49 sairecfifobuf2[i]=mymalloc(SRAMEX,SAI_RX_DMA_BUF_SIZE);//SAI接收FIFO內存申請 50 if(sairecfifobuf2[i]==NULL)break; //申請失敗 51 } 52 if(!tcp_server_sendbuf||i!=SAI_RX_FIFO_SIZE) re=1; 53 while(re); 54 LWIP_UNUSED_ARG(arg); //讓LWIP知道這個參數沒使用 55 56 conn = netconn_new(NETCONN_TCP); //創建一個新TCP鏈接 57 netconn_bind(conn,IP_ADDR_ANY,TCP_SERVER_PORT); //綁定端口 8087號端口 58 netconn_listen(conn); //將conn置為監聽狀態 59 conn->recv_timeout = 10; //禁止阻塞線程 等待10ms 如果不等待,由於netconn_recv函數的使用 會阻塞線程 60 while(1) 61 { 62 err = netconn_accept(conn,&newconn); //獲得一個新連接 63 if(err==ERR_OK) 64 { 65 newconn->recv_timeout = 10; //獲取連接成功 newconn禁止阻塞線程 等待10ms 66 67 struct netbuf *recvbuf; //創建一個netbuf格式的recvbuf 因為LWIP接收到數據包后會將數據封裝在一個 netbuf 中等待應用程序處理 68 69 netconn_getaddr(newconn,&ipaddr,&port,0); //獲取newconn連接的 客戶機IP地址和端口號 並存在ipaddr和port中 70 71 remot_addr[3] = (uint8_t)(ipaddr.addr >> 24); //遠端ip復制到remot_addr 72 remot_addr[2] = (uint8_t)(ipaddr.addr>> 16); 73 remot_addr[1] = (uint8_t)(ipaddr.addr >> 8); 74 remot_addr[0] = (uint8_t)(ipaddr.addr); 75 76 u8 *tbuf; //使用LCD需要 77 tbuf=mymalloc(SRAMIN,200); //申請內存 78 POINT_COLOR = BLUE; 79 sprintf((char*)tbuf,"Client IP:%d.%d.%d.%d",remot_addr[0],remot_addr[1],remot_addr[2],remot_addr[3]); //顯示客戶端IP 80 LCD_ShowString(30,170,210,16,16,tbuf); 81 POINT_COLOR = RED; 82 sprintf((char*)tbuf,"Local Port:%d",port); //客戶端端口號 83 LCD_ShowString(30,190,210,16,16,tbuf); 84 myfree(SRAMIN,tbuf); //一定要釋放內存否則會卡死 85 while(1) 86 { 87 88 //數據發送函數 89 //數據發送完畢后終止循環,一定使用NOCOPY模式!!! 90 91 wav_buffill(tcp_server_sendbuf); //將發送FIFO中的數據填充到tcp_server_sendbuf中 92 while(netconn_write(newconn,tcp_server_sendbuf,1460,NETCONN_NOCOPY)); //將tcp_server_sendbuf中的數據發送出去 93 OSTimeDlyHMSM(0,0,0,20); 94 95 96 97 //OSTimeDlyHMSM(0,0,0,100); //系統延時50ms 98 99 //數據接收函數 100 if((recv_err =netconn_recv(newconn,&recvbuf) ) == ERR_OK) //判斷是否收到數據 101 { 102 OS_ENTER_CRITICAL(); //關中斷 103 104 memset(tcp_server_recvbuf,0,TCP_SERVER_RX_BUFSIZE); //數據接收緩沖區清零 105 106 for(q = recvbuf->p;q!=NULL;q=q->next) //遍歷完整個pbuf鏈表 107 { 108 109 110 if(q->len > (TCP_SERVER_RX_BUFSIZE-data_len)) //判斷要拷貝到TCP_SERVER_RX_BUFSIZE中的數據是否大於TCP_SERVER_RX_BUFSIZE的剩余空間,如果大於的話就只拷貝TCP_SERVER_RX_BUFSIZE中剩余長度的數據 111 memcpy(tcp_server_recvbuf+data_len,q->payload,(TCP_SERVER_RX_BUFSIZE-data_len));//拷貝數據 112 else 113 memcpy(tcp_server_recvbuf+data_len,q->payload,q->len); 114 115 data_len += q->len; 116 117 if(data_len > TCP_SERVER_RX_BUFSIZE) 118 break; //超出TCP客戶端接收數組,跳出 119 } 120 rec_sai_fifo_write2(tcp_server_recvbuf); //將接收buf中的數據寫入接收FIFO中 121 recflag++; 122 123 OS_EXIT_CRITICAL(); //開中斷 124 data_len = 0; //復制完成后data_len要清零 125 netbuf_delete(recvbuf); //刪除recvbuf空間 否則會內存泄露 126 } 127 128 129 else if(recv_err == ERR_CLSD) //如果收到關閉連接的通知 130 { 131 netconn_close(newconn); //關閉newconn服務端 132 netconn_delete(newconn); //刪除服務端 否則會內存泄露 133 LCD_ShowString(30,170,210,16,16," "); 134 LCD_ShowString(30,190,210,16,16,"Connect closed "); 135 break; 136 } 137 } 138 } 139 } 140 } 141 142 143 144 145 146 //創建TCP服務器線程 147 //返回值:0 TCP服務器創建成功 148 // 其他 TCP服務器創建失敗 149 INT8U tcp_server_init(void) 150 { 151 INT8U res; 152 OS_CPU_SR cpu_sr; 153 154 OS_ENTER_CRITICAL(); //關中斷 155 res = OSTaskCreate(my_tcp_server_thread,(void*)0,(OS_STK*)&TCPSERVER_TASK_STK[TCPSERVER_STK_SIZE-1],TCPSERVER_PRIO); //創建TCP服務器線程 156 OS_EXIT_CRITICAL(); //開中斷 157 158 return res; 159 }
客戶端:
1 //tcp_client_demo.h 2 3 #ifndef __TCP_CLIENT_DEMO_H 4 #define __TCP_CLIENT_DEMO_H 5 #include "sys.h" 6 #include "includes.h" 7 8 9 10 #define TCP_CLIENT_RX_BUFSIZE 1460 //接收緩沖區長度 11 #define REMOTE_PORT 8087 //定義遠端主機的IP地址 12 #define LWIP_SEND_DATA 0X80 //定義有數據發送 13 14 15 extern u8 tcp_client_recvbuf[TCP_CLIENT_RX_BUFSIZE]; //TCP客戶端接收數據緩沖區 16 extern u8 tcp_client_flag; //TCP客戶端數據發送標志位 17 extern u8 recflag; 18 19 INT8U tcp_client_init(void); //tcp客戶端初始化(創建tcp客戶端線程) 20 #endif
1 //tcp_client_demo.c 2 3 #include "t" 4 #include "lwip/opt.h" 5 #include "lwip_comm.h" 6 #include "lwip/lwip_sys.h" 7 #include "lwip/api.h" 8 #include "includes.h" 9 #include "key.h" 10 #include "malloc.h" 11 #include "lcd.h" 12 #include "recorder.h" 13 14 struct netconn *tcp_clientconn; //TCP CLIENT網絡連接結構體 15 16 u8 tcp_client_recvbuf[TCP_CLIENT_RX_BUFSIZE]; //TCP客戶端接收數據緩沖區 17 18 u8 *tcp_Client_sendbuf; 19 u8 recflag=0; 20 21 22 23 //TCP客戶端任務 24 #define TCPCLIENT_PRIO 6 25 //任務堆棧大小 26 #define TCPCLIENT_STK_SIZE 300 27 //任務堆棧 28 OS_STK TCPCLIENT_TASK_STK[TCPCLIENT_STK_SIZE]; 29 30 void my_tcp_client_thread(void *arg) 31 { 32 OS_CPU_SR cpu_sr; 33 34 u32 data_len = 0; //已接收數據長度 35 struct pbuf *q; //定義一個數據包來存儲數據 36 err_t err,recv_err; //標志位 37 38 static ip_addr_t server_ipaddr,loca_ipaddr; //服務器IP 本地IP 39 40 static u16_t server_port,loca_port; //服務器端口 本地端口號 41 u8 server_ip[4]; 42 43 u8 i; 44 u8 re=0; 45 tcp_Client_sendbuf=mymalloc(SRAMEX,SAI_RX_DMA_BUF_SIZE); 46 47 for(i=0;i<SAI_RX_FIFO_SIZE;i++) 48 { 49 sairecfifobuf2[i]=mymalloc(SRAMEX,SAI_RX_DMA_BUF_SIZE);//SAI接收FIFO內存申請 50 if(sairecfifobuf2[i]==NULL)break; //申請失敗 51 } 52 if(!tcp_Client_sendbuf||i!=SAI_RX_FIFO_SIZE) re=1; 53 while(re); 54 55 56 LWIP_UNUSED_ARG(arg); //告訴LWIP這個參數沒用 57 58 server_port = REMOTE_PORT; //服務器端口為 8087 59 60 IP4_ADDR(&server_ipaddr, lwipdev.remoteip[0],lwipdev.remoteip[1], lwipdev.remoteip[2],lwipdev.remoteip[3]); //設置IPV4的地址即服務器地址為192.198.1.100 61 62 server_ip[0] = lwipdev.remoteip[0]; 63 server_ip[1] = lwipdev.remoteip[1]; 64 server_ip[2] = lwipdev.remoteip[2]; 65 server_ip[3] = lwipdev.remoteip[3]; 66 67 while (1) 68 { 69 tcp_clientconn = netconn_new(NETCONN_TCP); //創建一個TCP鏈接 70 71 err = netconn_connect(tcp_clientconn,&server_ipaddr,server_port); //一直連接服務器 72 73 if(err != ERR_OK) 74 netconn_delete(tcp_clientconn); //返回值不等於ERR_OK,刪除tcp_clientconn連接 75 else if (err == ERR_OK) //已經連接上了 處理新連接的數據 76 { 77 struct netbuf *recvbuf; //定義netbuf數據包 78 tcp_clientconn->recv_timeout = 10; // 延遲10ms禁止線程阻塞 79 netconn_getaddr(tcp_clientconn,&loca_ipaddr,&loca_port,1); //獲取本地IP主機IP地址和端口號 80 81 82 u8 *tbuf; //使用LCD需要 83 tbuf=mymalloc(SRAMIN,200); //申請內存 84 POINT_COLOR = BLUE; 85 sprintf((char*)tbuf,"Server IP:%d.%d.%d.%d",server_ip[0],server_ip[1],server_ip[2],server_ip[3]); //顯示服務器IP 86 LCD_ShowString(30,170,210,16,16,tbuf); 87 sprintf((char*)tbuf,"Local Port:%d",loca_port); //本地端口號 88 LCD_ShowString(30,190,210,16,16,tbuf); 89 myfree(SRAMIN,tbuf); //一定要釋放內存否則會卡死 90 91 while(1) 92 { 93 wav_buffill(tcp_Client_sendbuf); 94 while(netconn_write(tcp_clientconn ,tcp_client_recvbuf,1460,NETCONN_COPY)); 95 96 OSTimeDlyHMSM(0,0,0,20); 97 98 99 100 if((recv_err = netconn_recv(tcp_clientconn,&recvbuf)) == ERR_OK) //接收到數據 101 { 102 OS_ENTER_CRITICAL(); //關中斷 103 memset(tcp_client_recvbuf,0,TCP_CLIENT_RX_BUFSIZE); //數據接收緩沖區清零 104 105 for(q=recvbuf->p;q!=NULL;q=q->next) //遍歷完整個pbuf鏈表 106 { 107 if(q->len > (TCP_CLIENT_RX_BUFSIZE-data_len)) 108 memcpy(tcp_client_recvbuf+data_len,q->payload,(TCP_CLIENT_RX_BUFSIZE-data_len));//判斷要拷貝到TCP_CLIENT_RX_BUFSIZE中的數據是否大於TCP_CLIENT_RX_BUFSIZE的剩余空間,如果大於的話就只拷貝TCP_CLIENT_RX_BUFSIZE中剩余長度的數據,否則的話就拷貝所有的數據 109 else 110 memcpy(tcp_client_recvbuf+data_len,q->payload,q->len); 111 112 data_len += q->len; // 113 114 if(data_len > TCP_CLIENT_RX_BUFSIZE) 115 break; //超出TCP客戶端接收數組,跳出 116 } 117 rec_sai_fifo_write2(tcp_client_recvbuf); 118 recflag++; 119 120 OS_EXIT_CRITICAL(); //開中斷 121 122 123 data_len=0; //復制完成后data_len要清零。 124 netbuf_delete(recvbuf); 125 } 126 else if(recv_err == ERR_CLSD) //關閉連接 127 { 128 netconn_close(tcp_clientconn); 129 netconn_delete(tcp_clientconn); 130 LCD_ShowString(30,170,210,16,16," "); 131 LCD_ShowString(30,190,210,16,16,"Connect closed "); 132 break; 133 } 134 } 135 } 136 } 137 138 } 139 140 141 //創建TCP客戶端線程 142 //返回值:0 TCP客戶端創建成功 143 // 其他 TCP客戶端創建失敗 144 INT8U tcp_client_init(void) 145 { 146 INT8U res; 147 OS_CPU_SR cpu_sr; 148 149 OS_ENTER_CRITICAL(); //關中斷 150 res = OSTaskCreate(my_tcp_client_thread,(void*)0,(OS_STK*)&TCPCLIENT_TASK_STK[TCPCLIENT_STK_SIZE-1],TCPCLIENT_PRIO); //創建TCP客戶端線程 151 OS_EXIT_CRITICAL(); //開中斷 152 153 return res; 154 }