26.1 TCP協(xié)議概述
TCP是一種面向連接的,可靠地,基于IP的傳輸層協(xié)議,面向連接就意味著兩個(gè)實(shí)用TCP的應(yīng)用在進(jìn)行數(shù)據(jù)交換的時(shí)候必須先建立一個(gè)TCP連接,當(dāng)應(yīng)用層向TCP層發(fā)送用于傳輸?shù)?,?位字節(jié)表示的數(shù)據(jù)流,TCP先把數(shù)據(jù)流分割成適當(dāng)長(zhǎng)度的報(bào)文段,最大傳輸段的長(zhǎng)度MSS通常受計(jì)算機(jī)連接的網(wǎng)絡(luò)的數(shù)據(jù)鏈路層的最大傳輸單元MTU控制,之后TCP才把數(shù)據(jù)包傳給IP層,通過它來將數(shù)據(jù)傳送給接收端的TCP層。為了保證報(bào)文傳輸?shù)目煽啃?,?huì)給每個(gè)包一個(gè)序號(hào),同時(shí)序號(hào)也保證了傳送到接收端的數(shù)據(jù)報(bào)文能被按照順序接收,然后接收端對(duì)成功接收的報(bào)文發(fā)回一個(gè)響應(yīng)的確認(rèn)ACK,如果傳送端在合理的時(shí)間RTT內(nèi)沒有收到確認(rèn),那么對(duì)應(yīng)的數(shù)據(jù)就會(huì)被重傳TCP在數(shù)據(jù)正確性和合法性上采用一個(gè)校驗(yàn)和函數(shù)來測(cè)定數(shù)據(jù)是否有錯(cuò)誤,在發(fā)送和接收時(shí)都必須計(jì)算校驗(yàn)和,在保證可靠性上,對(duì)于窗口內(nèi)未經(jīng)確認(rèn)的分組需要重傳報(bào)文,在擁塞控制上,采用TCP擁塞控制算法。
TCP數(shù)據(jù)被封裝在一個(gè)IP數(shù)據(jù)報(bào)文中,IP數(shù)據(jù)報(bào)文結(jié)構(gòu)如下圖所示。
TCP報(bào)文數(shù)據(jù)格式在沒有選項(xiàng)的情況下,通常是20個(gè)字節(jié),數(shù)據(jù)結(jié)構(gòu)如下圖所示
(1)源端口號(hào)和目的端口號(hào)用于尋找發(fā)送端和接收端的應(yīng)用進(jìn)程,這個(gè)與UDP報(bào)文相同,這兩個(gè)值加上IP首部中的源IP地址和目的IP地址唯一確定了一個(gè)TCP連接。
(2)序列號(hào)字段用來標(biāo)識(shí)從TCP發(fā)送端向TCP接收端發(fā)送的數(shù)據(jù)字節(jié)流,用于表示在這個(gè)報(bào)文段中的第一個(gè)數(shù)據(jù)字節(jié),當(dāng)建立一個(gè)新的連接時(shí),握手報(bào)文中的SYN標(biāo)志置1,這個(gè)握手報(bào)文中的序號(hào)字段為隨機(jī)選擇的初始序號(hào)ISN(Initial Sequence Number),當(dāng)連接建立好以后發(fā)送方要發(fā)送的第一個(gè)字節(jié)序號(hào)為ISN+1。
(3)確認(rèn)號(hào)字段只有在ACK為1的時(shí)候才有用,確認(rèn)號(hào)中包含發(fā)送確認(rèn)的一方所期望接收到的下一個(gè)序號(hào),確認(rèn)號(hào)是在上一次成功接收到的數(shù)據(jù)字節(jié)序列號(hào)上加1,例如上次接收成功接收到對(duì)方發(fā)過來的數(shù)據(jù)序號(hào)為X,那么返回的確認(rèn)號(hào)就應(yīng)該為X+1
(4)頭部長(zhǎng)度又稱為首部長(zhǎng)度,首部長(zhǎng)度中給出了首部的長(zhǎng)度,以4個(gè)字節(jié)為單位,這個(gè)字段有4bit,因此TCP最多有60字節(jié)的首部,如果沒有任何的選項(xiàng)字段,正常的首部長(zhǎng)度是20字節(jié),TCP首部中還有6個(gè)標(biāo)志位,這6個(gè)標(biāo)志位如下表所示。
標(biāo)志位 | 說明 |
---|---|
URG | 置1時(shí)表示緊急指針有效 |
ACK | 置1時(shí)表示確認(rèn)序號(hào)字段有效 |
PSH | 置1表示接收方應(yīng)該盡快將這個(gè)報(bào)文段交給應(yīng)用層 |
RST | 置1表示重建連接 |
SYN | 用于發(fā)起連接 |
FIN | 發(fā)送端完成發(fā)送任務(wù),終止連接 |
(5)窗口尺寸也就是窗口大小,其中填寫相應(yīng)的值以通知對(duì)方期望接收的字節(jié)數(shù),窗口大小字段是TCP流量控制的關(guān)鍵字段,窗口大小是一個(gè)2個(gè)字節(jié)的字段,因此窗口大小最大為65535個(gè)字節(jié)。
(6)16位校驗(yàn)和和UDP的校驗(yàn)和計(jì)算原理相同,這是一個(gè)強(qiáng)制性的字段,校驗(yàn)和覆蓋整個(gè)TCP報(bào)文段。
(7)緊急指針只有在URG置1時(shí)有效,是一個(gè)正偏移量,和序號(hào)字段中的值相加表示緊急數(shù)據(jù)最后一個(gè)字節(jié)的序號(hào)。
tcp.c,tcp.h,tcp_in.c和tcp_out.c是LWIP中關(guān)于TCP協(xié)議的文件,TCP層中函數(shù)的關(guān)系如下圖所示。
常用的TCP協(xié)議的API函數(shù)如下表所示。
函數(shù)類型 | API函數(shù) | 功能 |
---|---|---|
建立TCP連接 | tcp_new() | 創(chuàng)建一個(gè)TCP的PCB控制塊 |
tcp_bind() | 為TCP的PCB控制塊綁定一個(gè)本地IP地址和端口號(hào) | |
tcp_listen() | 開始TCP的PCB監(jiān)聽 | |
tcp_accept() | 控制塊accept字段注冊(cè)的回調(diào)函數(shù),偵聽到連接時(shí)被調(diào)用 | |
tcp_accepted() | 通知LWIP協(xié)議棧一個(gè)TCP連接被接受了 | |
tcp_conect() | 連接遠(yuǎn)端主機(jī) | |
TCP數(shù)據(jù)發(fā)送 | tcp_write() | 構(gòu)造一個(gè)報(bào)文并放在控制塊的發(fā)送隊(duì)列緩沖中 |
tcp_sent() | 控制塊sent字段注冊(cè)的回調(diào)函數(shù),數(shù)據(jù)發(fā)送成功后被回調(diào) | |
tcp_output() | 將發(fā)送緩沖隊(duì)列中的數(shù)據(jù)發(fā)送出去 | |
TCP數(shù)據(jù)接收 | tcp_recv() | 控制塊recv字段注冊(cè)的回調(diào)函數(shù),當(dāng)接收到新數(shù)據(jù)時(shí)被調(diào)用 |
tcp_recved() | 當(dāng)程序處理完數(shù)據(jù)后一定要調(diào)用這個(gè)函數(shù),通知內(nèi)核更新接收窗口 | |
數(shù)據(jù)輪詢 | tcp_poll() | 控制塊poll字段注冊(cè)的回調(diào)函數(shù),該函數(shù)周期性調(diào)用 |
關(guān)閉和終止連接 | tcp_close() | 關(guān)閉TCP連接 |
tcp_err() | 控制塊err字段注冊(cè)的回調(diào)函數(shù),遇到錯(cuò)誤時(shí)被調(diào)用 | |
tcp_abort() | 中斷TCP連接 |
26.2 應(yīng)用編寫
26.2.1 tcp_client.c代碼編寫
#include "tcp_client.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "malloc.h"
#include "string.h"
#include "comm.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
//TCP Client 測(cè)試全局狀態(tài)標(biāo)記變量
//bit7:0,沒有數(shù)據(jù)要發(fā)送;1,有數(shù)據(jù)要發(fā)送
//bit6:0,沒有收到數(shù)據(jù);1,收到數(shù)據(jù)了
//bit5:0,沒有連接上服務(wù)器;1,連接上服務(wù)器了
//bit4~0:保留
u8 tcp_client_flag;
//設(shè)置遠(yuǎn)端IP地址
void tcp_client_set_remoteip()
{
u8 *tbuf;
tbuf=mymalloc( SRAMIN, 100 ) ; //申請(qǐng)內(nèi)存
if( tbuf==NULL )
return ;
//前三個(gè)IP保持和DHCP得到的IP一致
lwipdev.remoteip[ 0 ] = lwipdev.ip[ 0 ] ;
lwipdev.remoteip[ 1 ] = lwipdev.ip[ 1 ] ;
lwipdev.remoteip[ 2 ] = lwipdev.ip[ 2 ] ;
lwipdev.remoteip[ 3 ] = 113 ;
sprintf( ( char* )tbuf, "Remote IP:%d.%d.%d.", lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2] ) ;
LCD_ShowString( 30, 150, tbuf ) ; //遠(yuǎn)端IP
myfree( SRAMIN, tbuf ) ;
}
//關(guān)閉與服務(wù)器的連接
void tcp_client_connection_close( struct tcp_pcb *tpcb, struct tcp_client_struct *es )
{
tcp_abort( tpcb ) ; //終止連接,刪除pcb控制塊
tcp_arg( tpcb, NULL ) ;
tcp_recv( tpcb, NULL ) ;
tcp_sent( tpcb, NULL ) ;
tcp_err( tpcb, NULL ) ;
tcp_poll( tpcb, NULL, 0 );
if( es )
mem_free( es ) ;
tcp_client_flag &= ~( 1<<5 ) ; //標(biāo)記連接斷開了
}
// tcp_recv函數(shù)的回調(diào)函數(shù)
u8 tcp_client_recvbuf[ TCP_CLIENT_RX_BUFSIZE ] ; //接收數(shù)據(jù)緩沖區(qū)
err_t tcp_client_recv( void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err )
{
u32 data_len=0 ;
struct pbuf *q ;
struct tcp_client_struct *es ;
err_t ret_err ;
LWIP_ASSERT( "arg != NULL", arg!=NULL ) ;
es = ( struct tcp_client_struct* )arg ;
//如果從服務(wù)器接收到空的數(shù)據(jù)幀就關(guān)閉連接
if( p==NULL )
{
es->state = ES_TCPCLIENT_CLOSING ; //需要關(guān)閉TCP連接了
es->p = p ;
ret_err = ERR_OK ;
}
//當(dāng)接收到一個(gè)非空的數(shù)據(jù)幀,但是err!=ERR_OK
else if( err!=ERR_OK )
{
if( p )
pbuf_free( p ) ; //釋放接收pbuf
ret_err = err ;
}
//當(dāng)處于連接狀態(tài)時(shí)
else if( es->state==ES_TCPCLIENT_CONNECTED )
{
//當(dāng)處于連接狀態(tài)并且接收到的數(shù)據(jù)不為空時(shí)
if( p!=NULL )
{
memset( tcp_client_recvbuf, 0, TCP_CLIENT_RX_BUFSIZE ) ; //數(shù)據(jù)接收緩沖區(qū)清零
//遍歷完整個(gè)pbuf鏈表
for( q=p; q!=NULL; q=q->next )
{
if( q->len>( TCP_CLIENT_RX_BUFSIZE-data_len ) )
memcpy( tcp_client_recvbuf+data_len, q->payload, TCP_CLIENT_RX_BUFSIZE-data_len ) ;
else
memcpy( tcp_client_recvbuf+data_len, q->payload, q->len ) ;
data_len += q->len ;
//超出TCP客戶端接收數(shù)組,跳出
if( data_len>TCP_CLIENT_RX_BUFSIZE )
break ;
}
tcp_client_flag |= 1<<6 ; //標(biāo)記接收到數(shù)據(jù)了
tcp_recved( tpcb,p->tot_len ); //用于獲取接收數(shù)據(jù)
pbuf_free( p ) ; //釋放內(nèi)存
ret_err = ERR_OK ;
}
}
//接收到數(shù)據(jù)但是連接已經(jīng)關(guān)閉
else
{
tcp_recved( tpcb, p->tot_len ) ; //用于獲取接收數(shù)據(jù)
es->p = NULL ;
pbuf_free( p ) ; //釋放內(nèi)存
ret_err = ERR_OK ;
}
return ret_err ;
}
// tcp_err函數(shù)的回調(diào)函數(shù)
void tcp_client_error( void *arg, err_t err )
{
}
//發(fā)送數(shù)據(jù)
void tcp_client_senddata( struct tcp_pcb *tpcb, struct tcp_client_struct *es )
{
struct pbuf *ptr ;
err_t wr_err = ERR_OK ;
while( ( wr_err==ERR_OK )&&( es->p )&&( es->p->len<=tcp_sndbuf( tpcb ) ) )
{
ptr = es->p ;
wr_err = tcp_write( tpcb, ptr->payload, ptr->len, 1 ) ; //數(shù)據(jù)加入到發(fā)送緩沖隊(duì)列中
if( wr_err==ERR_OK )
{
es->p = ptr->next ; //指向下一個(gè)pbuf
//pbuf的ref加一
if( es->p )
pbuf_ref( es->p );
pbuf_free( ptr ) ; //釋放ptr
}
else if( wr_err==ERR_MEM )
es->p = ptr ;
tcp_output( tpcb ) ; //發(fā)送緩沖隊(duì)列中的數(shù)據(jù)發(fā)送
}
}
// tcp_sent的回調(diào)函數(shù)(從遠(yuǎn)端接收到ACK后發(fā)送數(shù)據(jù))
err_t tcp_client_sent( void *arg, struct tcp_pcb *tpcb, u16_t len )
{
struct tcp_client_struct *es ;
LWIP_UNUSED_ARG( len ) ;
es = ( struct tcp_client_struct* )arg ;
if( es->p )
tcp_client_senddata( tpcb, es ) ; //發(fā)送數(shù)據(jù)
return ERR_OK ;
}
// tcp_poll的回調(diào)函數(shù)
const u8 *tcp_client_sendbuf = "STM32F103 TCP Client send data\\r\\n" ; //TCP服務(wù)器發(fā)送數(shù)據(jù)內(nèi)容
err_t tcp_client_poll( void *arg, struct tcp_pcb *tpcb )
{
err_t ret_err ;
struct tcp_client_struct *es ;
es = ( struct tcp_client_struct* )arg ;
//連接處于空閑可以發(fā)送數(shù)據(jù)
if( es!=NULL )
{
//判斷是否有數(shù)據(jù)要發(fā)送
if( tcp_client_flag&( 1<<7 ) )
{
es->p = pbuf_alloc( PBUF_TRANSPORT, strlen( ( char* )tcp_client_sendbuf ), PBUF_POOL ) ;
pbuf_take( es->p, ( char* )tcp_client_sendbuf, strlen( ( char* )tcp_client_sendbuf ) ) ;
tcp_client_senddata( tpcb, es ) ; //將數(shù)據(jù)發(fā)送出去
tcp_client_flag &= ~( 1<<7 ) ; //清除數(shù)據(jù)發(fā)送標(biāo)志
//釋放內(nèi)存
if( es->p )
pbuf_free( es->p ) ;
}
else if( es->state==ES_TCPCLIENT_CLOSING )
tcp_client_connection_close( tpcb, es ) ; //關(guān)閉TCP連接
ret_err = ERR_OK ;
}
else
{
tcp_abort( tpcb ) ; //終止連接,刪除pcb控制塊
ret_err = ERR_ABRT ;
}
return ret_err ;
}
//連接建立后調(diào)用回調(diào)函數(shù)
err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
struct tcp_client_struct *es=NULL;
if(err==ERR_OK)
{
es = ( struct tcp_client_struct* )mem_malloc( sizeof( struct tcp_client_struct ) ) ; //申請(qǐng)內(nèi)存
//內(nèi)存申請(qǐng)成功
if( es )
{
es->state = ES_TCPCLIENT_CONNECTED ; //狀態(tài)為連接成功
es->pcb = tpcb ;
es->p = NULL ;
tcp_arg( tpcb, es ) ; //更新tpcb的callback_arg
tcp_recv( tpcb, tcp_client_recv ) ; //初始化tcp_recv回調(diào)功能
tcp_err( tpcb, tcp_client_error ) ; //初始化tcp_err()回調(diào)函數(shù)
tcp_sent( tpcb, tcp_client_sent ) ; //初始化tcp_sent回調(diào)功能
tcp_poll( tpcb, tcp_client_poll, 1 ) ; //初始化tcp_poll回調(diào)功能
tcp_client_flag |= 1<<5 ; //標(biāo)記連接到服務(wù)器了
err = ERR_OK ;
}
else
{
tcp_client_connection_close( tpcb, es ) ; //關(guān)閉連接
err = ERR_MEM ; //返回內(nèi)存分配錯(cuò)誤
}
}
else
tcp_client_connection_close( tpcb, 0 ) ; //關(guān)閉連接
return err ;
}
//客戶機(jī)測(cè)試
void tcp_client_test()
{
struct tcp_pcb *tcppcb ; //定義一個(gè)TCP服務(wù)器控制塊
struct ip_addr rmtipaddr ; //遠(yuǎn)端ip地址
u8 *tbuf ;
u8 res=0 ;
u8 t=0 ;
u8 connflag=0 ; //連接標(biāo)記
tcp_client_set_remoteip() ; //先選擇IP
tbuf = mymalloc( SRAMIN, 200 ) ; //申請(qǐng)內(nèi)存
//內(nèi)存申請(qǐng)失敗了,直接退出
if( tbuf==NULL )
return ;
sprintf( ( char* )tbuf, "Local IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 130, tbuf ) ; //服務(wù)器IP
sprintf( ( char* )tbuf, "Remote IP:%d.%d.%d.%d", lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2], lwipdev.remoteip[3] ) ;
LCD_ShowString( 30, 150, tbuf ) ; //遠(yuǎn)端IP
sprintf( ( char* )tbuf, "Remote Port:%d", TCP_CLIENT_PORT ) ; //客戶端端口號(hào)
LCD_ShowString( 30, 170, tbuf ) ;
LCD_ShowString( 30, 190, "STATUS:Disconnected" ) ;
tcppcb = tcp_new() ; //創(chuàng)建一個(gè)新的pcb
//創(chuàng)建成功
if( tcppcb )
{
IP4_ADDR( &rmtipaddr, lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2], lwipdev.remoteip[3] ) ;
tcp_connect( tcppcb, &rmtipaddr, TCP_CLIENT_PORT, tcp_client_connected ) ;
}
else
res = 1 ;
while( res==0 )
{
//是否收到數(shù)據(jù)
if( tcp_client_flag&1<<6 )
{
LCD_ShowString( 30, 230, tcp_client_recvbuf ) ; //顯示接收到的數(shù)據(jù)
tcp_client_flag |= 1<<7 ; //標(biāo)記要發(fā)送數(shù)據(jù)
tcp_client_flag &= ~( 1<<6 ) ; //標(biāo)記數(shù)據(jù)已經(jīng)被處理了
}
//是否連接上
if( tcp_client_flag&1<<5 )
{
if( connflag==0 )
{
LCD_ShowString( 30, 190, "STATUS:Connected " ) ;
LCD_ShowString( 30, 210, "Receive Data:" ) ;
connflag = 1 ; //標(biāo)記連接了
}
}
else if( connflag )
{
LCD_ShowString( 30, 190, "STATUS:Disconnected" ) ;
connflag = 0 ; //標(biāo)記連接斷開了
}
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
t ++ ;
if( t==200 )
{
//未連接上,則嘗試重連
if( ( connflag==0 )&&( ( tcp_client_flag&1<<5 )==0 ) )
{
tcp_client_connection_close( tcppcb, 0 ) ; //關(guān)閉連接
tcppcb = tcp_new() ; //創(chuàng)建一個(gè)新的pcb
//創(chuàng)建成功
if( tcppcb )
tcp_connect( tcppcb, &rmtipaddr, TCP_CLIENT_PORT, tcp_client_connected ) ;
}
t = 0 ;
}
}
tcp_client_connection_close( tcppcb, 0 ) ; //關(guān)閉TCP Client連接
myfree( SRAMIN, tbuf ) ;
}
26.2.2 tcp_client.h代碼編寫
#ifndef _TCP_CLIENT_H_
#define _TCP_CLIENT_H_
#include "sys.h"
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
#define TCP_CLIENT_RX_BUFSIZE 1500 //最大接收數(shù)據(jù)長(zhǎng)度
#define TCP_CLIENT_TX_BUFSIZE 200 //最大發(fā)送數(shù)據(jù)長(zhǎng)度
#define LWIP_SEND_DATA 0x80 //有數(shù)據(jù)發(fā)送
#define TCP_CLIENT_PORT 8087 //遠(yuǎn)端端口
//tcp服務(wù)器連接狀態(tài)
enum tcp_client_states
{
ES_TCPCLIENT_NONE = 0, //沒有連接
ES_TCPCLIENT_CONNECTED, //連接到服務(wù)器了
ES_TCPCLIENT_CLOSING, //關(guān)閉連接
};
//LWIP回調(diào)函數(shù)使用的結(jié)構(gòu)體
struct tcp_client_struct
{
u8 state; //當(dāng)前連接狀
struct tcp_pcb *pcb; //指向當(dāng)前的pcb
struct pbuf *p; //指向接收/或傳輸?shù)膒buf
};
void tcp_client_test( void ) ; //TCP Client測(cè)試函數(shù)
#endif
26.2.3 主函數(shù)代碼編寫
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "tim.h"
#include "lcd.h"
#include "malloc.h"
#include "dm9000.h"
#include "lwip/netif.h"
#include "comm.h"
#include "lwipopts.h"
#include "tcp_client.h"
int main()
{
u8 buf[ 30 ];
STM32_Clock_Init( 9 ) ; //系統(tǒng)時(shí)鐘設(shè)置
SysTick_Init( 72 ) ; //延時(shí)初始化
USART1_Init( 72, 115200 ) ; //串口初始化為115200
LCD_Init() ; //初始化LCD
TIM3_Init( 1000, 719 ) ; //定時(shí)器3頻率為100hz
my_mem_init( SRAMIN ) ; //初始化內(nèi)部?jī)?nèi)存池
while( lwip_comm_init() ) ; //lwip初始化
//等待DHCP獲取成功/超時(shí)溢出
while( ( lwipdev.dhcpstatus!=2 )&&( lwipdev.dhcpstatus!=0xFF ) )
{
lwip_periodic_handle() ; //LWIP內(nèi)核需要定時(shí)處理的函數(shù)
lwip_pkt_handle() ;
}
POINT_COLOR=RED;
LCD_ShowString( 30, 110, "LWIP Init Successed" ) ;
//打印動(dòng)態(tài)IP地址
if( lwipdev.dhcpstatus==2 )
sprintf( ( char* )buf, "DHCP IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
//打印靜態(tài)IP地址
else
sprintf( ( char* )buf, "Static IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 130, buf ) ;
//得到網(wǎng)速
if( ( DM9000_Get_SpeedAndDuplex()&0x02 )==0x02 )
LCD_ShowString( 30, 150, "Ethernet Speed:10M" ) ;
else
LCD_ShowString( 30, 150, "Ethernet Speed:100M" ) ;
while( 1 )
{
tcp_client_test() ;
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
}
}
26.3 實(shí)驗(yàn)結(jié)果
-
TCP
+關(guān)注
關(guān)注
8文章
1390瀏覽量
79648 -
MSS
+關(guān)注
關(guān)注
0文章
5瀏覽量
6771 -
傳輸層協(xié)議
+關(guān)注
關(guān)注
0文章
6瀏覽量
1313
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
LABVIEW實(shí)現(xiàn)網(wǎng)絡(luò)通信的方法
四種在LabVIEW中實(shí)現(xiàn)網(wǎng)絡(luò)通信的方法
labview TCP客戶端
【NanoPi NEO試用體驗(yàn)】TCP通信之客戶端程序
android的Tcp網(wǎng)絡(luò)通信
基于LABVIEW實(shí)現(xiàn)網(wǎng)絡(luò)通信的方法
請(qǐng)問在做網(wǎng)絡(luò)通信試驗(yàn)時(shí),PC端一般是客戶端還是服務(wù)器?
為什么網(wǎng)絡(luò)通信實(shí)驗(yàn)用TCP客戶端模式時(shí)連接不上?
為什么網(wǎng)絡(luò)通信實(shí)驗(yàn)在網(wǎng)絡(luò)助手上接受到的先是456個(gè)字節(jié)?
STM32F103上網(wǎng)絡(luò)通信實(shí)驗(yàn)中服務(wù)器與客戶端連接但不能進(jìn)行數(shù)據(jù)交換該怎么辦?
基于原子STM32F4的攝像頭與網(wǎng)絡(luò)通信實(shí)驗(yàn)
stm32f107vc lwip tcp客戶端
基于TCP/IP的網(wǎng)絡(luò)通信應(yīng)用程序分享
網(wǎng)絡(luò)調(diào)試和串口調(diào)試集合UDP TCP客戶端和TCP服務(wù)器端應(yīng)用程序免費(fèi)下載

評(píng)論