上一節我們對TCP的報文和連接過程做了介紹,本節通過Socket的方式對整個通信過程再次進行一次整理(使用Socket方式易于加深對以太網通信過程的理解,在此講解使用的是完整版Socket)。
服務器端初始化
1)調用socket,向內核申請一個套接字sock
2)調用bind將sock與服務器端的IP與PORT綁定
3)調用listen將套接字設為監聽模式,準備接收客戶端連接請求
4)調用accept等待并接收客戶端的連接請求,建立好TCP連接后,該函數會返回一個新的已連接套接字connected
創建連接
1)客戶端調用socket創建套接字
2)調用connect,向服務器發送連接請求
3)connect會發送一個請求SYN段并阻塞等待服務器應答(第一次握手)
4)服務器收到SYN,會給客戶端發送一個確認應答ACK,同時發送一個請求(SYN)建立連接(第二次握手)
5)客戶端收到服務器發的SYN+ACK段,表明客戶端連接已建立成功,進入已連接狀態。客戶端再向服務器發送一個ACK段,服務器收到后則服務器連接成功
數據傳輸
1)服務器端使用accept連接建立成功后(通信雙方可同時寫數據,支持全雙工),調用read開始讀數據,若沒有數據則阻塞等待
2)客戶端調用write向服務器發送數據請求,客戶端收到之后調用read處理請求,此過程服務器調用read阻塞等待
3)服務器調用write將處理好的請求發送給客戶端,再次調用read等待下一個請求
4)服務器收到SYN,會給客戶端發送一個確認應答ACK,同時發送一個請求(SYN)建立連接(第二次握手)
4)客戶端收到后從read返回,發送下一條請求,如此循環下去
斷開連接
1)沒有數據,則客戶端調用close關閉連接,給服務器發送一個斷開連接請求FIN段(第一次握手)
2)服務器收到客戶端的FIN段,給客戶端發送一個確認應答ACK段,表明同意斷開連接。客戶端收到ACK段并調用read返回0,表明客戶端連接已經斷開(第二次握手)
3)read返回0后,服務器知道客戶端已經斷開連接,它也調用close關閉連接,給客戶端發送一個斷開連接請求FIN段(第三次握手)
4)客戶端收到服務器發送的FIN段,就給服務器一個確認應答ACK段,表明同意斷開連接。客戶端進入TIME_WAIT狀態,服務器收到客戶端的ACK段后也斷開連接
實驗使用MB-039開發板,在應用工程中使用LwIP+FreeRTOS,實驗展示如何制作一個TCP Server_socket,并收發數據,實驗使用到的硬件如下:
如圖是MB-039(完整原理圖可以通過MM32官網下載)的Ethermac部分。
各個信號引腳對應如下:
Server_socket實驗用到的API大部分在前面已經進行講解(只是對NETCONN接口編輯方式進行二次封裝),本節只介紹一個比較關鍵的API:setsockopt(s,level,optname,opval,optlen)。
從名稱中就可以看出函數功能用于設置套接字的一些選項,我們關注一下參數:
(1)level有多個常用的選項
SOL_SOCKET:表示在Socket層
IPPROTO_TCP:表示在TCP層
IPPROTO_IP:表示在IP層
(2)optname 表示該層的具體選項名稱
level為SOL_SOCKET時,有以下選項:SO_REUSEADDR(允許重用本地地址和端口)、
SO_SNDTIMEO(設置發送數據超時時間)、SO_SNDTIMEO(設置接收數據超時時間)、SO_RCVBUF(設置發送數據緩沖區大小)等。
level為IPPROTO_TCP時,有以下選項:TCP_NODELAY(不使用Nagle算法)、TCP_KEEPALIVE(設置TCP保活時間)等。
level為IPPROTO_IP選項,有以下選項:IP_TTL(設置生存時間)、IP_TOS(設置服務類型)等。
實現Server_socket函數:
static void server_socket(void* thread_param) { int sock = -1, connected; char* recv_data; struct sockaddr_in server_addr, client_addr; socklen_t sin_size; int recv_data_len; printf("The local port number is%dnn", LOCAL_PORT); recv_data = (char*)pvPortMalloc(RECV_DATA); if (recv_data == NULL) { printf("No memoryn"); goto __exit; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { printf("Socket errorn"); goto __exit; } server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(LOCAL_PORT); memset( (server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); if (bind(sock, (struct sockaddr*) server_addr, sizeof(struct sockaddr)) == -1) { printf("Unable to bindn"); goto __exit; } if (listen(sock, 5) == -1) { // (1) printf("Listen errorn"); goto __exit; } while(1) { sin_size = sizeof(struct sockaddr_in); connected = accept(sock, (struct sockaddr*) client_addr, sin_size); // (2) printf("new client connected from (%s, %d)n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); { int flag = 1; setsockopt(connected, IPPROTO_TCP, /* set option at TCP level */ TCP_NODELAY, /* name of option */ (void*) flag, /* the cast is historical cruft */ sizeof(int)); /* length of option value */ // (3) } while(1) { recv_data_len = recv(connected, recv_data, RECV_DATA, 0); // (4) if (recv_data_len <= 0) break; printf("recv %d len datan", recv_data_len); write(connected, recv_data, recv_data_len); // (5) } if (connected >= 0) closesocket(connected); // (6) connected = -1; } __exit: if (sock >= 0) closesocket(sock); if (recv_data) free(recv_data); }
1)進入監聽狀態
2)阻塞應用線程直至與遠端主機建立TCP連接,建立成功后遠程主機的信息將保持在連接句柄中(connected)
3)對套接字connected進行設置:在TCP層,不使用Nagle算法
4)處理客戶端的連接請求,接收遠程主機信息
5)將接收的數據進行轉發
6)主動關閉客戶端的連接
到這里已經完成了Server_socket函數的創建,看一下PC的IP地址,設備需要處于同一網段方便測試。打開命令行窗口輸入:ipconfig
PC的地址為:192.168.105.34,在sys_arch.h文件中對DEST_IP_ADDR0 、DEST_IP_ADDR1、DEST_IP_ADDR2、DEST_IP_ADDR3進行修改,DEST_PORT 隨意修改。
#define LOCAL_PORT 2021 #define IP_ADDR0 192 #define IP_ADDR1 168 #define IP_ADDR2 105 #define IP_ADDR3 26
將程序下載入開發板中,使用NetAssist進行如下設置:
1)協議設置,此時設備為Server,則PC為Client
2)設置遠程主機地址(即設備地址)
3)端口號
點擊連接,若提示連接失敗,則Ping一下開發板地址,可以正常Ping通則檢查端口號;如果無法Ping通則需要對工程進行檢查。
任意輸入字符進行發送。
通過上圖可以觀察到發送成功,并且設備返回數據與發送數據一致,表明實驗成功。
實驗程序請登錄我們的官網下載MM32F3270 SDK,工程路徑如下:
~MM32F3270_Lib_Samples_V0.90Demo_appEthernet_DemoETH_RTOSFreertos_Server_socket
來源:靈動MM32MCU
審核編輯:湯梓紅
-
以太網
+關注
關注
40文章
5460瀏覽量
172741 -
通信
+關注
關注
18文章
6072瀏覽量
136428 -
Server
+關注
關注
0文章
93瀏覽量
24116 -
TCP
+關注
關注
8文章
1378瀏覽量
79303
發布評論請先 登錄
相關推薦
評論