Windows程序设计基础第八章TCP/IP和网络通信•8.1网络基础知识网络是可以交换数据的互相连接的计算机的集合。LAN(LocalNetwork)WAN(WideAreaNetwork)Internet协议是一组规定,它描述了数据传送的格式以及如何通过网络交流数据.网络是建立在协议之上的.•以太网(Ethernet)1.介质访问控制层以太网的最底层,硬件层。网卡属于该层,包括了串行网络接口和一个控制器.控制器帮助将原始数据转换为电子信号,并发送到正确位置.MAC地址:48位的标识.在最底层通过MAC号进行寻址.2.网际协议层寻址方式:IP地址。IP地址通过软件分配给网络接口,这时会将IP地址和网络接口的MAC地址关联在一起。为了使用IP寻址,关联的MAC地址需要保存起来。这由ARP负责。每个主机都维护了一个记录IP和MAC地址对的清单。如果用户使用的IP地址没有在此清单中,主机会发出一个询问到局域网中的其它计算机,以获取与之相匹配的MAC地址。如果此局域网中有计算机可以识别此IP地址,它送回对应的MAC地址,如果没有,封包就会被送到网关—发送封包到外部网络的计算机。3.传输控制协议层IP之上是TCP层,这层离网络应用程序非常近。TCP为寻址增加了最后一个限制----端口号。IP地址用来寻址指定的计算机或者网络设备,而端口号涌来确定运行在目的计算机上的哪个应用程序应该接收这个封包。端口号是16位的,范围:0---65536之内。TCP层关心传输是否成功,要确保数据正确的到达。也让接收者控制数据流动,数据丢失,TCP重发。4.软件层TCP之上是网络软件。在Windows下,应用程序不直接访问TCP层,而是通过WinsockAPI访问。软件层提供了非常方便的访问网络的方式。由于所有下层协议的存在,在软件层不必担心封包、封包大小、数据错误、对丢失包的重发等。如图是以太网接口堆栈中每个协议的封装形式。他们都是从软件层开始的。软件层包含了用户请求发送的数据,有时这块数据会有固定的格式。用户数据首先取得包含源端口号和目的端口号的TCP头。然后添加IP头,它包含发送者和接受者的IP地址。最后数据链路层添加以太网头,它指定了发送者和接收者的MAC地址,这是真正通过电缆发送的数据。•以太网接口堆栈EthernetheaderIPheaderTcpheaderUserdata硬件IPheaderTcpheaderUserdataTcpheaderUserdataUserdata用户软件层TCP层IP层链路层MAC以太网接口堆栈TCP/IP是面向连接的协议。连接的两个设备之间。每一方都使用自己的IP地址和端口号。通常,一方称为客户,另一方称为服务器。客户是发送请求方,服务器响应它们。服务器通常是等待客户连接,这叫监听,这一般是在特定的IP地址和端口号进行。服务器和客户方都需要使用IP地址和端口号。服务器的通常是固定的。•服务器/客户机模型•8.2Winsock接口Winsock是处理网络的WindowsAPI.•套节字的概念和类型通信双方要建立连接,这个连接的终端就是套节字。客户端和服务器都有一个套节字。每个套节字都和特定的IP地址和端口号关联。几乎所有的Winsock函数都在套节字上进行操作,因为套节字是到连接的句柄。连接的两端都要使用一个套节字,他们与平台无关。套节字是双通的,即同一个套节字既能够接收也能够发送数据。•8.2Winsock接口套节字的类型:流套节字(SOCK_STREAM):为需要可靠连接的应用程序设计。这些程序经常使用连续的数据流。协议是TCP。一些众所周知的协议HTTP、TCP、SMTP、POP3等都使用它。数据报套节字(SOCK_DGRAM):无连接的。有一个最大缓冲区大小(数据包大小的最大值)。它是为那些需要发送小数据包,并且对可靠性要求不高的应用程序设计。不保证数据会到达终端,也不保证是正确的顺序到来。传输效率相当高。经常用于音频或视频应用程序。•Winsock的寻址方式和字节顺序寻址方式:通用方式---IP地址和端口号Structsockaddr_in{shortsin_family;//地址家族(即指定地址格式)u_shortsin_port;//端口号structin_addrsin_addr;//IP地址charsin_zero[8];//空字节,设为0}字节顺序:长度跨越多个字节的数据被存储的顺序。TCP/IP协议统一使用大尾方式传输数据,也称为网络字节顺序。•Winsock编程流程1.Winsock库的装入、初始化和释放所有Winsock函数都是从WS2_32.DLL库导入的。VC++默认情况下并没有连接到该库。如果想使用WinsockAPI,就必须包含相应的库文件.#pragmacomment(lib,”wsock32.lib”)WSAstratup必须是首先调用的Winsock函数。允许应用程序指定所需的WindowsSocketsAPI版本,获取特定Winsock实现的详细信息。仅当这个函数成功执行之后,应用程序才能调用其它WinsockAPI版本。intWSAStratup(WORDwVersionRequested,//应用程序支持的最高Winsock版本,//高字节为次版本号,低字节为主版本号。LPWSADATAlpWSAData//一个指向WSADATA结构的指针。用来返//回DLL库的详细信息。);调用函数成功返回0。否则调用WSAGetLastError函数查看出错的原因。它必须对应调用下面函数释放Winsock库:intWSACleanup(void);•套节字的创建和关闭使用套节字之前,必须调用socket函数创建一个套节字对象,此函数调用成功将返回套节字句柄。SOCKETsocket(intaf,//用来指定套节字使用的地址格式,WinSock中只支持AF_INETinttype,//用来指定套节字的类型intprotocol//配合type参数的使用,用来指定使用的协议类型。可以是IPPROTO_TCP);关闭套节字:intclosesocket(SOCKETs);//套节字句柄绑定套节字到指定的IP地址和端口号为套节字关联本地地址的函数是bind。intbind(SOCKETs,//套节字句柄Conststructsockaddr*name,//要关联的本地地址intnamelen//地址的长度);Bind函数用在没有建立连接的套节字上,它的作用是绑定面向连接的或者无连接的套节字。设置套节字进入监听状态listen函数置套节字进入监听状态。intlisten(SOCKETs,//套节字句柄intbacklog//监听队列中允许保持的尚未处理的最大连接数量);接受连接请求SOCKETaccept(SOCKETs,//套节字句柄structsockaddr*addr,//一个指向sockaddr_in的指针,用于取得对方地址信息int*addrlen//指向地址长度的指针)客户端程序在创建套节字之后,要使用connect函数请求与服务器连接。intconnect(SOCKETs,//套节字句柄conststructsockaddrFAR*name,//指针,包含要连接的服务器的地址信息intnamelen//sockaddr_in结构的长度)•收发数据intsend(SOCKETs,//套节字句柄constcharFAR*buf,//要发送数据的缓冲区地址intlen,//缓冲区长度intflags//指定了调用方式,通常设为0);intrecv(SOCKETs,charFAR*buf,intlen,intflags);send函数在一个连接的套节字上发送缓冲区内的数据,返回发送数据的实际字节数。recv函数从对方接收数据,并存储它到指定的缓冲区。编程思路•8.3服务器和客户方程序举例结束