您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > TCP、UDP通信程序设计实验
实验六TCP、UDP通信程序设计实验2客户1客户2服务器请求应答请求应答通信程序基础:客户端和服务器3N+1层协议实体N层协议实体N-1层协议实体响应指示N+1层协议实体N层协议实体N-1层协议实体请求证实使用的服务提供的服务IPv4,IPv6EthernetAdapterApp1App2portAportBTCPUDP通信程序基础:分层4TCP通信实验cont15得到ip地址建立tcp连接:构造http数据包,向tcp请求构造tcp数据包,承载http包构造ip数据包得到mac地址构造数据帧通信程序基础:实例67Socket介绍(1)什么是socket?先看文件操作的例子:通过open函数得到一个文件的文件描述符;然后对这个描述符进行读写OS|Application1Application2file得到一个整数来标识这个文件,称为filedescriptor得到一个整数来标识这个文件把用来标识这个文件整数看作是这个入口的标识把用来标识这个文件的整数看作是这两入口的标识8Socket介绍(2)OS|ProtocolmoduleNetworkOSProtocolmoduleApplication1Application1socketsocketSocketdescriptor用类似于open的函数得到一个socket描述符,然后对这个描述符进行读写操作9从网络整体来看,socket是不同主机上应用程序之间的一个虚拟的接口,具有跨平台特性。从程序员角度来看,它是应用程序和网络设备的一个接口,特殊的I/O从操作系统看,它是一种资源。如同handle用来描述windows中的窗口等资源,socket用socketdescriptor来标识。Socket介绍(3)10字节流套接口(StreamSockets)面向连接的,位于TCP之上数据报套接口(DatagramSockets)无连接的,位于UDP之上原始套接口(RawSockets)直接发送和处理IP包:例如pingSocket介绍(4)11Socket的起源最初在70年代由加州大学Berkeley分校开发,其目的是为BSD(BerkeleySoftwareDistribution)UNIX4.1版操作系统提供网络通信接口。Socket在各种平台下的发展随着BerkeleySockets的广泛应用,九十年代初,Sun、MS等公司共同制定了适应dos和win平台的windowssockets的规范(WinSock)SunMicrosystems为Java也制定了网络通信的APILinux下的socket继承了BSDsockets的风格,并有所改动不同的网络有不同的套接口CCITTX.25套接口Berkeley套接口Socket介绍(5)12现在开始具体介绍socket编程。由前面的叙述可以看出,我们要进行通信就要得到对应的socketdescriptor,一旦得到了,对它进行读写操作就可以了,例如intread(intfd,char*buf,intlen);intwrite(intfd,char*buf,intlen);在与另一台计算机通信之前要知道对方的什么信息?IP地址或者域名端口(用来区分不同的应用)Socket介绍(6)13Socket用下面的结构体来描述一个IP地址socket.h结构中sa_family为套接口的协议族地址类型,例如对于通常的TCP/IP协议(IPv4),它的值是AF_INET;sa_data中存储着具体的协议地址,不同的协议族有不同的地址格式。sa_data的存储内容往往是包含地址和端口信息,而仅使用一个变量,使用起来不太方便——定义新的Socket地址结构Socket介绍(7)structsockaddr{unsignedshortsa_family;/*地址家族2字节*/charsa_data[14];/*14字节协议地址*/};14新版的socket地址的定义最后的那个元素是填充的空白信息,这样就保持整个结构与sockaddr结构的长度相同Socket介绍(8)structsockaddr_in{shortintsin_family;/*通信类型2字节*/unsignedshortintsin_port;/*端口,2字节*/structin_addrsin_addr;/*Internet地址,4字节*/unsignedcharsin_zero[8];}注意理解指针和类型强制转换15Socket介绍(9)structin_addr{unsignedlongs_addr;};图中的紫色部分就是端口和IP地址。这两个域必须是网络字节顺序NetworkByteOrderstructsockaddr_in{shortintsin_family;/*通信类型2字节*/unsignedshortintsin_port;/*端口,2字节*/structin_addrsin_addr;/*Internet地址,4字节*/unsignedcharsin_zero[8];}16structin_addr{union{struct{unsignedchars_b1;unsignedchars_b2;unsignedchars_b3;unsignedchars_b4;}S_un_b;struct{unsignedshorts_w1;unsignedshorts_w2;}S_un_w;unsignedlongS_addr;}S_un;};17sockaddr只是一个抽象的概况形式,并不实用sockaddr_in更加结合了TCP/IP协议族的特点,易于使用,所以编程中常使用这个结构。但是:socket本身所封装的API都是支持sockaddr结构的,所以填充sockaddr_in结构需要强制转换成sockaddr结构,方可作为参数被socket的标准函数所使用。例如:intconnect(intsockfd,structsockaddr*servaddr,unsignedintaddrlen)Socket介绍(10)18字节顺序主机字节顺序(HostByteOrder)低位在前,高位在后(little-endian)基于Intel芯片的机器采取这种存储方式网络字节顺序(NetworkByteOrder)高位在前,低位在后(big-endian)Sockaddr_in的变量成员(端口和地址)都必须使用网络字节顺序字节顺序19例如端口34567的16进制表示是0x8707。如果定义变量unsignedshortsin_port=3456707870x111111110x11111112主机字节序….681fe334870736….网络字节序以字节为最小单位,但是计算机对内存的读取是双字节的如果是ip地址202.38.75.11的16进制表示。如果定义变量unsignedlongs_addr=0xCA264B0B0x222222220x222222250B4B26CA….681fCA264B0B12….26CA0B4B20字节顺序转换字节顺序的函数(in.h)uint16_thtons(uint16_t);uint16_tntohs(uint_16_t);uint32_thtonl(uint32_t);uint32_tntohl(uint32_t);‘h’:host‘n’:network‘s’:short(16bit)‘l’:long(32bit)例如:定义structsockaddr_insh;unsignedshortport=12345;sh.sin_port=htons(port);htons和ntohs的实现是一样的;htonl和ntohl一样21前面提到的几个函数对于IP地址的转换仍然不方便,因为首先得得到ip地址的数值表示,而我们习惯于用带点的字符串来表示,如“202.38.75.11”因此希望有函数能处理这样的请求:给一个字符串如“202.38.75.11”能返回相应的网络字节序的unsignedlong值给一个unsignedlong的值能返回一个字符串字节顺序22•inet_aton•intinet_aton(constchar*cp,structin_addr*inp);•例如将“192.168.0.10”转化为0xC0A8000A•inet_addr•unsignedlonginet_addr(constchar*cp);•功能同上,但不能处理广播地址•inet_ntoa•char*inet_ntoa(structin_addrin);•例如将0xC0A8000A转化为“192.168.3.10”23TCP通信实验注意bind和listensocket()bind()listen()accept()write()read()read()TCPServerclose()socket()TCPClientconnect()write()read()close()建立连接客户请求服务器响应结束连接24基本套接口函数(1)-socket()intfd;/*socketdescriptor*/if((fd=socket(AF_INET,SOCK_STREAM,0))0)}fprintf(stderr,“socketcreatingerror\n”);exit(1);}/*注:在TCP或UDP编程的时候,protocol都取0*/类型(type)SOCK_STREAMSOCK_DGRAMSOCK_RAW解释字节流套接口数据报套接口原始套接口domain=AF_INETTCPUDPIPv4#includesys/socket.hintsocket(intdomain,inttype,intprotocol);创建socket返回:非负整数描述符表示成功,-1表示出错domain一般设为AF_INET,protocol一般设为025基本套接口函数(2)-connect()#includesys/socket.hintconnect(intsockfd,structsockaddr*servaddr,unsignedintaddrlen);返回:0表示成功,-1表示出错connect()由客户使用,旨在和服务器建立一个连接。sockfd是函数socket()返回的套接口描述符,servaddr表示远程服务器的套接口,addrlen表示套接口地址的长度注意:之前要先调用socket()创建套接口26TCP通信-客户端例子intfd;/*套接口描述符*/structsockaddr_insrv;/*套接口地址结构*/fd=socket(AF_INET,SOCK_STREAM,0);/*connect:AF_INET表示使用Internet地址族*/srv.sin_family=AF_INET;/*connect:目标是连向服务器的8000号端口*/srv.sin_port=htons(8000);/*connect:目标服务器的IPAddress是“202.38.75.11”*/srv.sin_addr.s_addr=inet_addr(“202.38.75.11”);if(connect(fd,(structsockaddr*)&srv,sizeof(srv))0){fprintf(stderr,”connecterror!\n);exit(1);}27基本套接口函数(3)-bind()#includesys/socket.hintbind(intsockfd,structsockaddr*servaddr,unsignedintaddrlen);返回:0表示成功,-1表示出错bind将本机地址(某个或全部地址)与套接口绑定在一起一般用于服务器绑定自己公认的服务端口号客户端一般会在调
本文标题:TCP、UDP通信程序设计实验
链接地址:https://www.777doc.com/doc-6455530 .html