当前位置:文档之家› 视频信息处理与传输实验3

视频信息处理与传输实验3

实验三 TCP一、实验目的1、认识TCP 协议的相关内容;2、掌握TCP 模块的C 语言编程; 二、实验内容1、创建一个头文件,用C 语言实现TCP 模块所需的所有常量;2、完成TCP 首部的说明;最大报文段长度MSS(Maximum Segment Size)是TCP 报文段中的数据字段的最大长度。

MSS 告诉对方TCP :“我的缓存所能接收的报文段的数据字段的最大长度是MSS 个字节。

”窗口扩大因子,用于长肥管道。

时间戳,可用于测量往返时延RTT 。

3、完成TCP 报文段的说明;图1 TCP 报文结构源端口和目的端口字段——各占2字节。

端口是传输层与应用层的服务接口。

传输层的复用和分用功能都要通过端口才能实现。

序号字段——占4字节。

TCP 连接中传送的数据流中的每一个字节都编上一个序号。

序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。

确认号字段——占4字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。

数据偏移——占4bit ,它指出TCP 报文段的数据起始处距离 CP 报文段的起始处有多远。

“数据偏移”的单位不是字节而是32bit 字(4字节为计算单位)。

保留字段——占6bit ,保留为今后使用,但目前应置为0。

紧急比特URG ——当URG =1时,表明紧急指针字段有效。

它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。

确认比特ACK ——只有当ACK =1时确认号字段才有效。

当ACK =0时,确认号无效。

复位比特RST(Reset) —— 当RST =1时,表明TCP 连接中出现严重差错URG 紧急数据 (一般不用) ACK 序号有效 立即提交数据 RST, SYN, FIN: 连接建立(建立和拆连)SYN :是握手信号 FIN :拆除连接接收方允许 的字节数对数据字节计数(并非对报文段计数!)(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。

同步比特SYN——同步比特SYN置为1,就表示这是一个连接请求或连接接受报文。

终止比特FIN(FINal)——用来释放一个连接。

当FIN=1时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。

窗口字段——占2字节。

窗口字段用来控制对方发送的数据量,单位为字节。

TCP连接的一端根据设置的缓存空间大小确定自己的接收窗口大小,然后通知对方以确定对方的发送窗口的上限。

检验和——占2字节。

检验和字段检验的范围包括首部和数据这两部分。

在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。

紧急指针字段——占16bit。

紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。

选项字段——长度可变。

TCP首部可以有多达40字节的可选信息,用于把附加信息传递给终点,或用来对齐其它选项。

填充字段——这是为了使整个首部长度是4字节的整数倍。

4、用C语言写出TCP有限状态机的实现函数。

TCP从建立到终止整个过程中,存在11中状态,TCP的有限状态机给出了TCP连接从一个状态转换到另一个状态的规则。

客户进程服务器进程非正常状体转换图2 TCP有限状态机三、实验过程1、TCP头文件:#ifndef _TCP_H#define _TCP_H#ifndef _GLOBAL_H#include "global.h"#endif#ifndef _MBUF_H#include "mbuf.h"#endif#ifndef _IFACE_H#include "iface.h"#endif#ifndef _INTERNET_H#include "internet.h"#endif#ifndef _IP_H#include "ip.h"#endif#ifndef _NETUSER_H#include "netuser.h"#endif#ifndef _TIMER_H#include "timer.h"#endif#define DEF_MSS 512 /* Default maximum segment size */#define DEF_WND 2048 /* Default receiver window */#define RTTCACHE 16 /* # of TCP round-trip-time cache entries */ #define DEF_RTT 5000 /* Initial guess at round trip time (5 sec) */#define MSL2 30 /* Guess at two maximum-segment lifetimes */ #define MIN_RTO 500L /* Minimum timeout, milliseconds */#define TCP_HDR_PAD 70 /* mbuf size to preallocate for headers */#define DEF_WSCALE 0 /* Our window scale option */#define geniss() ((int32)msclock() << 12) /* Increment clock at 4 MB/sec */ /* Number of consecutive duplicate acks to trigger fast recovery */#define TCPDUPACKS 3/* Round trip timing parameters */#define AGAIN 8 /* Average RTT gain = 1/8 */#define LAGAIN 3 /* Log2(AGAIN) */#define DGAIN 4 /* Mean deviation gain = 1/4 */#define LDGAIN 2 /* log2(DGAIN) */#define TCPLEN 20 /* Minimum Header length, bytes */#define TCP_MAXOPT 40 /* Largest option field, bytes */2、TCP首部struct TCP_header{unsigned short SPortAddru_char ver_ihl; // 版本(4 bits) + 首部长度(4 bits) == 8u_char tos; // 服务类型(Type of service)u_short tlen; // 总长(Total length)u_short identification; // 标识(Identification)u_short flags_fo; // 标志位(3 bits) + 段偏移量(Fragment offset) (13 bits)u_char ttl; // 存活时间(Time to live)u_char proto; // 协议(Protocol)u_short crc; // 首部校验和(Header checksum)ip_address saddr; // 源地址(Source address)ip_address daddr; // 目的地址(Destination address)u_int op_pad; // 选项与填充(Option + Padding)}ip_header;3、TCP报文段struct TCP_Segment{struct TCP_Header tcpHeader;uint16 source; /* Source port */uint16 dest; /* Destination port */int32 seq; /* Sequence number */int32 ack; /* Acknowledgment number */uint16 wnd; /* Receiver flow control window */uint16 checksum; /* Checksum */uint16 up; /* Urgent pointer */uint16 mss; /* Optional max seg size */uint8 wsopt; /* Optional window scale factor */uint32 tsval; /* Outbound timestamp */uint32 tsecr; /* Timestamp echo field */struct {unsigned int congest:1; /* Echoed IP congestion experienced bit */unsigned int urg:1;unsigned int ack:1;unsigned int psh:1;unsigned int rst:1;unsigned int syn:1;unsigned int fin:1;unsigned int mss:1; /* MSS option present */unsigned int wscale:1; /* Window scale option present */unsigned int tstamp:1; /* Timestamp option present */ tcpData;}};4、TCP有限状态机#include "global.h"#include "timer.h"#include "mbuf.h"#include "netuser.h"#include "internet.h"#include "tcp.h"#include "ip.h"voidtcp_output(tcb)register struct tcb *tcb;{struct mbuf *dbp; /* Header and data buffer pointers */struct tcp seg; /* Local working copy of header */uint16 ssize; /* Size of current segment being sent,* including SYN and FIN flags */uint16 dsize; /* Size of segment less SYN and FIN */int32 usable; /* Usable window */int32 sent; /* Sequence count (incl SYN/FIN) already* in the pipe but not yet acked */int32 rto; /* Retransmit timeout setting */if(tcb == NULL) return;switch(tcb->state){case TCP_LISTEN:case TCP_CLOSED:return; /* Don't send anything */}for(;;){memset(&seg,0,sizeof(seg));/* Compute data already in flight */sent = tcb->snd.ptr - tcb->snd.una;usable = min(tcb->snd.wnd,tcb->cwind);if(usable > sent) usable -= sent; /* Most common case */else if(usable == 0 && sent == 0) usable = 1; /* Closed window probe */else usable = 0; /* Window closed or shrunken */ssize = min(tcb->sndcnt - sent,usable);ssize = min(ssize,tcb->mss);if(!tcb->flags.force && sent != 0 && ssize < tcb->mss&& !(tcb->state == TCP_FINWAIT1 && ssize == tcb->sndcnt-sent)){ ssize = 0;}if(!tcb->flags.synack && !Tcp_syndata){if(tcb->snd.ptr == tcb->iss) ssize = min(1,ssize); /* Send only SYN */else ssize = 0; /* Don't send anything */}if(tcb->flags.force && tcb->snd.ptr != tcb->snd.nxt) ssize = 0;if(ssize == 0 && !tcb->flags.force)break; /* No need to send anything */tcb->flags.force = 0; /* Only one forced segment! */seg.source = tcb->conn.local.port;seg.dest = tcb->conn.remote.port;seg.flags.ack = 1; /* Every state except TCP_SYN_SENT */seg.flags.congest = tcb->flags.congest;if(tcb->state == TCP_SYN_SENT)seg.flags.ack = 0; /* Haven't seen anything yet */dsize = ssize;if(!tcb->flags.synack && tcb->snd.ptr == tcb->iss){/* Send SYN */ seg.flags.syn = 1;dsize--; /* SYN isn't really in snd queue *//* Also send MSS, wscale and tstamp (if OK) */seg.mss = Tcp_mss;seg.flags.mss = 1;seg.wsopt = DEF_WSCALE;seg.flags.wscale = 1;if(Tcp_tstamps){seg.flags.tstamp = 1;seg.tsval = msclock();}}if(ssize == 0) seg.seq = tcb->snd.nxt;else seg.seq = tcb->snd.ptr;tcb->last_ack_sent = seg.ack = tcb->rcv.nxt;if(seg.flags.syn || !tcb->flags.ws_ok) seg.wnd = tcb->rcv.wnd; else seg.wnd = tcb->rcv.wnd >> tcb->rcv.wind_scale;dbp = ambufw(TCP_HDR_PAD+dsize);dbp->data += TCP_HDR_PAD; /* Allow room for other hdrs */if(dsize != 0){int32 offset;offset = sent;if(!tcb->flags.synack && sent != 0) offset--;dbp->cnt = extract(tcb->sndq,(uint16)offset,dbp->data,dsize);if(dbp->cnt != dsize){/* We ran past the end of the send queue;*/ seg.flags.fin = 1;dsize--;}}if(dsize != 0 && sent + ssize == tcb->sndcnt) seg.flags.psh = 1;if(tcb->snd.ptr < tcb->snd.nxt)tcb->resent += min(tcb->snd.nxt - tcb->snd.ptr,ssize);tcb->snd.ptr += ssize;if(seq_gt(tcb->snd.ptr,tcb->snd.nxt)) tcb->snd.nxt = tcb->snd.ptr; if(tcb->flags.ts_ok && seg.flags.ack){seg.flags.tstamp = 1;seg.tsval = msclock();seg.tsecr = tcb->ts_recent;}/* Generate TCP header, compute checksum, and link in data */htontcp(&seg,&dbp,tcb->conn.local.address,tcb->conn.remote.address)if(ssize != 0){/* Set round trip timer. */rto = backoff(tcb->backoff) * (4 * tcb->mdev + tcb->srtt);set_timer(&tcb->timer,max(MIN_RTO,rto));if(!run_timer(&tcb->timer))start_timer(&tcb->timer);/* If round trip timer isn't running, start it */if(tcb->flags.ts_ok || !tcb->flags.rtt_run){tcb->flags.rtt_run = 1;tcb->rtt_time = msclock();tcb->rttseq = tcb->snd.ptr;tcb->rttack = tcb->snd.una;}}if(tcb->flags.retran) tcpRetransSegs++;else tcpOutSegs++;ip_send(tcb->conn.local.address,tcb->conn.remote.address,TCP_PTCL,tcb->tos,0,&dbp,len_p(dbp),0,0);}}四、实验小结通过本次实验,认识到自己对于理论知识学习的不足以,所以在以后的学习中继续努力。

相关主题