网络编程主讲人:孙鑫
http://www.sunxin.org
计算机网络
计算机网络是相互连接的独立自主的计算机的集合,最简单的网络形式由两台计算机组成。
http://www.sunxin.org
两台计算机通过网络进行通信
A B网络
192.168.0.118 192.168.0.10
协议 协议端口号端口号
http://www.sunxin.org
IP地址
IP网络中每台主机都必须有一个惟一的 IP
地址;
IP地址是一个逻辑地址;
因特网上的 IP地址具有全球唯一性;
32位,4个字节,常用点分十进制的格式表示,例如,192.168.0.16
http://www.sunxin.org
协议
为进行网络中的数据交换(通信)而建立的规则、标准或约定。 (=语义 +语法 +规则 )
不同层具有各自不同的协议。
http://www.sunxin.org
网络的状况
多种通信媒介 —— 有线、无线 ……
不同种类的设备 —— 通用、专用 ……
不同的操作系统 —— Unix,Windows ……
不同的应用环境 —— 固定、移动 ……
不同业务种类 —— 分时、交互、实时 ……
宝贵的投资和积累 —— 有形、无形 ……
用户业务的延续性 —— 不允许出现大的跌宕起伏。
它们互相交织,形成了非常复杂的系统应用环境。
http://www.sunxin.org
网络异质性问题的解决
网络体系结构 就是使这些用不同媒介连接起来的不同设备和网络系统在不同的应用环境下实现互操作性,并满足各种业务需求的一种粘合剂,它营造了一种,生存空间,—— 任何厂商的任何产品、以及任何技术只要遵守这个空间的行为规则,
就能够在其中生存并发展。
网络体系结构 解决异质性问题采用的是分层方法 —— 把复杂的网络互联问题划分为若干个较小的、单一的问题,在不同层上予以解决。
就像我们在编程时把问题分解为很多小的模块来解决一样。
http://www.sunxin.org
ISO/OSI七层参考模型
OSI(Open System Interconnection)参考模型将网络的不同功能划分为 7层。
应用层表示层物理层会话层传输层网络层数据链路层处理网络应用数据表示主机间通信端到端的连接寻址和最短路径介质访问 (接入 )
二进制传输
http://www.sunxin.org
ISO/OSI七层参考模型
通信实体的对等层之间不允许直接通信。
各层之间是严格单向依赖。
上层使用下层提供的服务 — Service user;
下层向上层提供服务 — Service provider。
http://www.sunxin.org
对等通信示例
“你好,
“Hello”
传真中国教师翻译秘书
“Hallo”
“Hello”
传真德国教师翻译秘书对交谈内容的共识用英语对话使用传真通信
P3
P2
P1
物理通信线路
http://www.sunxin.org
对等层通信的实质
对等层实体之间虚拟通信。
下层向上层提供服务,实际通信在最底层完成。
http://www.sunxin.org
OSI各层所使用的协议
应用层,远程登录协议 Telnet、文件传输协议 FTP、
超文本传输协议 HTTP、域名服务 DNS、简单邮件传输协议 SMTP、邮局协议 POP3等。
传输层:传输控制协议 TCP、用户数据报协议
UDP。
TCP:面向连接的可靠的传输协议。
UDP:是无连接的,不可靠的传输协议。
网络层:网际协议 IP,Internet互联网控制报文协议 ICMP,Internet组管理协议 IGMP。
http://www.sunxin.org
数据封装
一台计算机要发送数据到另一台计算机,数据首先必须打包,打包的过程称为 封装 。
封装就是在数据前面加上特定的协议头部。
数据数据协议头
http://www.sunxin.org
数据封装
OSI参考模型中,对等层协议之间交换的信息单元统称为协议数据单元 (PDU,Protocol Data Unit)。
OSI参考模型中每一层都要依靠下一层提供的服务。
为了提供服务,下层把上层的 PDU作为本层的数据封装,
然后加入本层的头部(和尾部)。头部中含有完成数据传输所需的控制信息。
这样,数据自上而下递交的过程实际上就是不断封装的过程。到达目的地后自下而上递交的过程就是不断拆封的过程。由此可知,在物理线路上传输的数据,其外面实际上被包封了多层,信封,。
但是,某一层只能识别由对等层封装的,信封,,而对于被封装在,信封,内部的数据仅仅是拆封后将其提交给上层,本层不作任何处理。
http://www.sunxin.org
TCP/IP模型
TCP/IP起源于美国国防部高级研究规划署
(DARPA)的一项研究计划 —— 实现若干台主机的相互通信。
现在 TCP/IP已成为 Internet上通信的工业标准。
TCP/IP模型包括 4个层次:
应用层
传输层
网络层
网络接口
http://www.sunxin.org
TCP/IP与 OSI参考模型的对应关系应用层表示层会话层传输层物理层数据链路层网络层
7
6
5
4
3
2
1
OSI参考模型应用层传输层网络接口网络层
TCP/IP模型
http://www.sunxin.org
端口
按照 OSI七层模型的描述,传输层提供进程(应用程序)
通信的能力。为 了标识通信实体中进行通信的进程(应用程序),TCP/IP协议提出了协议端口( protocol port,简称端口)的概念。
端口是一种抽象的软件结构(包括一些数据结构和 I/O缓冲区)。应用程序通过系统调用与某端口建立连接( binding)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都通过该端口输出。
端口用一个整数型标识符来表示,即端口号。端口号跟协议相关,TCP/IP传输层的两个协议 TCP和 UDP是完全独立的两个软件模块,因此各自的端口号也相互独立。
端口使用一个 16位的数字来表示,它的范围是 0~65535,
1024以下的端口号保留给预定义的服务。例如,http使用
80端口。
http://www.sunxin.org
套接字 (socket)的引入
为了能够方便的开发网络应用软件,由美国伯克利大学在
Unix上推出了一种应用程序访问通信协议的操作系统调用
socket(套接字 )。 socket的出现,使程序员可以很方便地访问 TCP/IP,从而开发各种网络应用的程序。
随着 Unix的应用推广,套接字在编写网络软件中得到了极大的普及。后来,套接字又被引进了 Windows等操作系统,
成为开发网络应用程序的非常有效快捷的工具。
套接字存在于通信区域中。通信区域也叫地址族,它是一个抽象的概念,主要用于将通过套接字通信的进程的共有特性综合在一起。套接字通常只与同一区域的套接字交换数据(也有可能跨区域通信,但这只在执行了某种转换进程后才能实现)。 Windows Sockets只支持一个通信区域:
网际域 ( AF_INET),这个域被使用网际协议簇通信的进程使用。
http://www.sunxin.org
网络字节顺序
不同的计算机存放多字节值的顺序不同,
有的机器在起始地址存放低位字节 (低位先存 ),有的机器在起始地址存放高位字节 (高位先存 )。基于 Intel的 CPU,即我们常用的
PC机采用的是低位先存。为保证数据的正确性,在网络协议中需要指定网络字节顺序。 TCP/IP协议使用 16位整数和 32位整数的高位先存格式。
http://www.sunxin.org
客户机/服务器模式
在 TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机 /服务器模式 (client/server),即客户向服务器提出请求,服务器接收到请求后,提供相应的服务。
客户机 /服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,
需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,
又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户机 /服务器模式的 TCP/IP。
http://www.sunxin.org
客户机/服务器模式
客户机 /服务器模式在操作过程中采取的是主动请求的方式。
首先服务器方要先启动,并根据请求提供相应的服务:
①打开一个通信通道并告知本地主机,它愿意在某一地址和端口上接收 客户请求。
②等待客户请求到达该端口。
③接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务 请求,要激活一个新的进程 (或线程 )来处理这个客户请求。新进程 (或线程 ) 处理此客户请求,并不需要对其它请求作出应答。服务完成后,
关闭此新进程与客户的通信链路,并终止。
④返回第二步,等待另一客户请求。
⑤关闭服务器。
客户方:
①打开一个通信通道,并连接到服务器所在主机的特定端口。
②向服务器发服务请求报文,等待并接收应答;继续提出请求。
③请求结束后关闭通信通道并终止。
http://www.sunxin.org
Windows Sockets的实现
Windows Sockets是 Microsoft Windows的网络程序设计接口,
它是从 Berkeley Sockets扩展而来的,以动态链接库的形式提供给我们使用。 Windows Sockets在继承了 Berkeley
Sockets主要特征的基础上,又对它进行了重要扩充。这些扩充主要是提供了一些异步函数,并增加了符合 Windows
消息驱动特性的网络事件异步选择机制。
Windows Sockets 1.1和 Berkeley Sockets都是基于 TCP/IP协议的; Windows Sockets 2从 Windows Sockets 1.1发展而来,与协议无关并向下兼容,可以使用任何底层传输协议提供的通信能力,来为上层应用程序完成网络数据通讯,而不关心底层网络链路的通讯情况,真正实现了底层网络通讯对应用程序的透明。
http://www.sunxin.org
套接字的类型
流式套接字( SOCK_STREAM)
提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。
数据报式套接字( SOCK_DGRAM)
提供无连接服务。数据包以独立包形式发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。
原始套接字( SOCK_RAW)。
http://www.sunxin.org
基于 TCP(面向连接 )的 socket编程服务器端程序:
1、创建套接字( socket)。
2、将套接字绑定到一个本地地址和端口上( bind)。
3、将套接字设为监听模式,准备接收客户请求( listen)。
4、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字( accept)。
5、用返回的套接字和客户端进行通信( send/recv)。
6、返回,等待另一客户请求。
7、关闭套接字。
客户端程序:
1、创建套接字( socket)。
2、向服务器发出连接请求
( connect)。
3、和服务器端进行通信
( send/recv)。
4、关闭套接字。
http://www.sunxin.org
基于 UDP(面向无连接 )的 socket编程服务器端(接收端)程序:
1、创建套接字( socket)。
2、将套接字绑定到一个本地地址和端口上( bind)。
3、等待接收数据( recvfrom)。
4、关闭套接字。
客户端(发送端)程序:
1、创建套接字( socket)。
2、向服务器发送数据( sendto)。
3、关闭套接字。
http://www.sunxin.org
相关函数说明
int WSAStartup( WORD wVersionRequested,
LPWSADATA lpWSAData );
wVersionRequested参数用于指定准备加载的 Winsock
库的版本。高位字节指定所需要的 Winsock库的副版本,而低位字节则是主版本。可用
MAKEWORD(x,y)(其中,x是高位字节,y是低位字节 )方便地获得 wVersionRequested的正确值。
lpWSAData参数是指向 WSADATA结构的指针,
WSAStartup用其加载的库版本有关的信息填在这个结构中。
http://www.sunxin.org
续:
WSADATA结构定义如下:
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA,*LPWSADATA;
WSAStartup把第一个字段 wVersion设成打算使用的 Winsock版本。 wHighVersion 参数容纳的是现有的 Winsock库的最高版本。记住,这两个字段中,高位字节代表的是 Winsock副版本,而低位字节代表的则是 Winsock主版本。 szDescription和 szSystemStatus这两个字段由特定的 Winsock实施方案设定,
事实上没有用。不要使用下面这两个字段,iMaxSockets和 iMaxUdpDg,它们是假定同时最多可打开多少套接字和数据报的最大长度。然而,要知道数据报的最大长度应该通过 WSAEnumProtocols来查询协议信息。同时最多可打开套接字的数目不是固定的,很大程度上和可用物理内存的多少有关。 最后,lpVendorInfo字段是为 Winsock实施方案有关的指定厂商信息预留的。任何一个 Win32平台上都没有使用这个字段。
如果 WinSock.dll或底层网络子系统没有被正确初始化或没有被找到,WSAStartup将返回
WSASYSNOTREADY。此外这个函数允许你的应用程序协商使用某种版本的 WinSock规范,如果请求的版本等于或高于 DLL所支持的最低版本,WSAData的 wVersion成员中将包含你的应用程序应该使用的版本,它是 DLL所支持的最高版本与请求版本中较小的那个。反之,如果请求的版本低于
DLL所支持的最低版本,WSAStartup将返回 WSAVERNOTSUPPORTED。关于 WSAStartup更详细的信息,请查阅 MSDN中的相关部分。
对于每一个 WSAStartup的成功调用 (成功加载 WinSock DLL后 ),在最后都对应一个 WSACleanUp调用,以便释放为该应用程序分配的资源。
http://www.sunxin.org
相关函数说明
SOCKET socket( int af,int type,int protocol );
该函数接收三个参数。第一个参数 af指定地址族,对于
TCP/IP协议的套接字,它只能是 AF_INET(也可写成
PF_INET)。第二个参数指定 Socket类型,对于 1.1版本的
Socket,它只支持两种类型的套接字,SOCK_STREAM指定产生流式套接字,SOCK_DGRAM产生数据报套接字。
第三个参数是与特定的地址家族相关的协议,如果指定为
0,那么它就会根据地址格式和套接字类别,自动为你选择一个合适的协议。这是推荐使用的一种选择协议的方法。
如果这个函数调用成功,它将返回一个新的 SOCKET数据类型的套接字描述符。如果调用失败,这个函数就会返回一个 INVALID_SOCKET,错误信息可以通过
WSAGetLastError函数返回。
http://www.sunxin.org
相关函数说明
int bind( SOCKET s,const struct sockaddr FAR *name,int namelen );
这个函数接收三个参数。第一个参数 s指定要绑定的套接字,第二个参数指定了该套接字的本地地址信息,是指向 sockaddr结构的指针变量,
由于该地址结构是为所有的地址家族准备的,这个结构可能(通常会)
随所使用的网络协议不同而不同,所以,要用第三个参数指定该地址 结构的长度。 sockaddr结构定义如下:
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
sockaddr的第一个字段 sa_family指定该地址家族,在这里必须设为
AF_INET。 sa_data仅仅是表示要求一块内存分配区,起到占位的作用,
该区域中指定与协议相关的具体地址信息。由于实际要求的只是内存 区,所以对于不同的协议家族,用不同的结构来替换 sockaddr。除了
sa_family外,sockaddr是按网络字节顺序表示的。在 TCP/IP中,我们可以用 sockaddr_in结构替换 sockaddr,以方便我们填写地址信息。
http://www.sunxin.org
续:
sockaddr_in的定义如下:
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
其中,sin_family表示地址族,对于 IP地址,sin_family成员将一直是
AF_INET。成员 sin_port指定的是将要分配给套接字的端口。成员 sin_addr给出的是套接字的主机 IP地址。而成员 sin_zero只是一个填充数,以使
sockaddr_in结构和 sockaddr结构的长度一样。如果这个函数调用成功,它将返回 0。如果调用失败,这个函数就会返回一个 SOCKET_ERROR,错误信息可以通过 WSAGetLastError函数返回。
将 IP地址指定为 INADDR_ANY,允许套接字向任何分配给本地机器的 IP
地址发送或接收数据。多数情况下,每个机器只有一个 IP地址,但有的机器可能会有多个网卡,每个网卡都可以有自己的 IP地址,用 INADDR_ANY可以简化应用程序的编写。将地址指定为 INADDR_ANY,允许一个独立应用接受发自多个接口的回应。如果我们只想让套接字使用多个 IP中的一个地址,就必须指定实际地址,要做到这一点,可以用 inet_addr()函数,这个函数需要一个字符串作为其参数,该字符串指定了以点分十进制格式表示的 IP地址 (如
192.168.0.16)。而且 inet_addr()函数会返回一个适合分配给 S_addr的 u_long类型的数值。 inet_ntoa()函数会完成相反的转换,它接受一个 in_addr结构体类型的参数并返回一个以点分十进制格式表示的 IP地址字符串。
http://www.sunxin.org