Scoket编程
网络应用程序指的是针对网络边缘上用户主机开发的应用,并不包括路由器等上的应用
计算机网络五层模型:
在现在的网络环境中开发一个网络应用程序有哪些途径:
- 面向网卡编程(硬件相关)
- 基于Packet Driver编程(屏蔽网卡所有细节;适用于所有网卡)
- 基于NDIS网络编程
- 基于LibPcap/WinPcap、Libnet、Libnids、Libicmp编程
- NetBIOS编程
- Scoket编程
- Web/RPC/中间插件编程
应用编程接口(API)
1:应用程序接口主要指的是应用层和传输层之间的接口
2:网络应用程序就是指在应用层运行的应用层进程之间的通信问题
3:应用层协议定义了应用层进程间如何交互,交互信息内容等
4:应用进程和操作系统的传输层协议交互需要接口:把应用层数据传输给传输层
5:应用程序接口API:就是应用进程的控制权和操作系统的控制权进行转换的一个系统调用接口
6:几种常用的应用编程接口
- 套接字接口(简称套接字):Berkeley UNIX定义的一种API
- WINSOCK:微软公司在其操作系统中采用了套接字接口,形成的一个稍有不同的API
- TLI(传输层接口)
Scoket API
1.最初设计
- 面向BSD UNIX-Berkley
- 面向TCP/IP协议栈接口
2.目前
- 事实上的工业标准
- 绝大多数操作系统都支持
3.Internet网络应用最典型的API接口
4.通信模型——客户/服务器
5.应用进程间通信的抽象机制
4.
- 在一台主机上,应用层可能会有很多应用进程在运行。
- 每一个服务器应用进程为了能够支持客户端的客户和它进行通信,按照套接字的机制,它必须创建套接字。
- 一个进程可能要创建多个套接字,不同进程创建不同的套接字,当一个客户创建套接字期望与某一个服务器进行通信的时候,通过IP地址和端口号(套接字接口的编号,16位整数)明确与哪一个服务器应用进程进行通信。
- 标识通信端口(对外):IP地址+端口号
- 操作系统/进程如何管理套接字(对内):套接字描述符(小整数)
5.Socket抽象
- 类似于文件的抽象
- 当应用进程创建套接字时,操作系统分配一个数据结构存储套接字的相关信息
- 返回套接字描述符
注:端点地址=IP地址+端口号
6.地址结构
- 已定义结构sockaddr_in:
- 使用TCP/IP协议簇的网络应用程序声明端点地址变量时,使用结构sockaddr_in
7.Socket API函数(WinSock)
1)WSAStartup
- int WSAStartup(WORD wVersionRequested, LPWSADATA IpWSAData);
- 使用Socket的应用程序在使用Socket之前必须首先调用WSAStartup函数
- 两个参数
- 第一个参数指明程序请求使用的WinSock版本,其中高位字节指明副版本,低位字节指明主版本(十六进制整数,例如0x102表示2.1版)
- 第二个参数返回实际的WinSock的版本信息(指向WSADATA结构的指针)
- 例:使用2.1版的WinSock的程序代码段
2)WSACleanup
- int WSACleanup(void);
- 应用程序在完成对请求的Scoket库使用时,最后要调用WSACleanup函数
- 解除与Scoket库的绑定
- 释放Scoket库所占用的系统资源
3)socket
- sd = socket(protofamily,type,proto);
- 创建套接字
- 操作系统返回套接字描述符(sd)
- 第一个参数(协议族):protofamily = PF_INET(TCP/IP)
- 第二个参数(套接字类型):type = SOCK_STREAM,SOCK_DGRAM or SOCK_RAW(TCP/IP)
- 第三个参数(协议号):0为默认
- 例:创建一个流套接字的代码段
4)Closesocket
- int closesocket(SOCKET sd);
- 关闭一个描述符为sd的套接字
- 如果多个进程共享一个套接字,调用closesocket将套接字引用计数减1,减至0后才关闭
- 一个进程中的多线程对一个套接字的使用无计数(如果进程中的一个线程调用closesocket将一个套接字关闭,该进程中的其他线程也将不能访问该套接字)
- 返回值:【0:成功;SOCKET_ERROR:失败】
5)bind
- int bind(sd,localaddr,addrlen);
- 绑定套接字的本地端点地址(IP地址+端口号)
- 参数
- sd:套接字描述符
- localaddr:端点地址(结构:sockaddr_in)
- 客户程序一般不必调用bind函数(默认端口号)
- 服务器端:调用bind函数来指定服务器端熟知端口号;服务器绑运行主机的IP地址
5. 服务器端利用bind绑定端点地址时,除了设置端口号,IP地址需赋为INADDR_ANY;
6)listen(仅用于服务器端)
- int listen (sd,queuesize);
- 置服务器端的流套接字处于监听状态(仅服务器端调用;仅用于面向连接的流套接字)
- 设置连接请求队列大小
- 返回值(0:成功;SOCKET_ERROR:失败)
7)connect
- connect (sd , saddr ,saddrlen)
- 客户程序调用connect函数来使客户端套接字(sd)与特定计算机的特定端口(saddr)的套接字(服务)进行连接
- 仅用于客户端
- 可用于TCP客户端(建立TCP连接)也可用于UDP客户端(指定服务器端点地址)
8)accept(仅用于服务器端)
- newsock = accept ( sd ,caddr ,caddrlen);
- 服务程序调用accept函数从处于监听状态的流套接字sd的客户连接请求队列中取出排在最前面的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道(仅用于TCP套接字;仅用于服务器)
- 利用新创建的套接字与客户通信
9)send,sendto
- send (sd, *buf, len, flags);
- sendto(sd, *buf, len, flags, destaddr, addelen);
- send函数TCP套接字(客户与服务器)或调用了connect函数的UDP客户端套接字
- sendto函数用于UDP服务器端套接字与未调用connect函数的UDP客户端套接字
10)recv,recvfrom
- recv(sd, *buffer, len, flags);
- recvfrom(sd, *buf, len , flags, senderaddr, saddrlen);
- recv函数从TCP连接的另一端接收数据,或者从调用了connect函数的UDP客户端套接字接收服务器发来的数据
- recvfrom函数用于从UDP服务器端套接字与未调用connect函数的UDP客户端套接字接收对端数据
11)setsockopt,getsockopt
- int setsockopt(int sd, int level, int optname ,*optval, int optlen);
- int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen);
- setsockopt()函数用来设置套接字sd的选项参数
- getsockopt()函数用于获取任意类型,任意状态套接口的选项当前值,并把结果存入optval
12)Socket API函数小结
8.Socket面向TCP/IP的服务类型
应用进程间进行通信要创建套接字,套接字架起了应用层和传输层间的接口
流套接字SOCK_STREAM:创建的套接字面向TCP协议【TCP提供的数据传输:可靠(不会出错,不会丢失,不会乱序等),面向连接(数据传输前必须建立TCP连接),字节流传输,点对点(一个TCP连接只能连接两种,不能连接第三方),全双工】
数据报套接字SOCK_DGRAM:创建的套接字面向UDP协议【UDP提供的数据传输:不可靠,无连接(数据发送时,双方不需要事先交互,直接发送),数据报传输】
原始套接字Sock_RAW:创建的套接字直接面向网络层
9.网络字节顺序
- TCP/IP定义了标准的用于协议头中的二进制整数表示:网络字节顺序
- 某些Socket API函数的参数需要存储为网络字节顺序(如IP地址,端口号等)
- 可以实现本地字节顺序与网络字节顺序之间的转换的函数
10.网路应用的Socket API(TCP)调用基本流程
客户端软件设计
解析服务器IP地址
1)客户端可能使用域名(如:study.163.com)或IP地址(123.58.180.121)标识服务器
2)IP协议需要使用32位二进制IP地址
3)需要将域名或IP地址转换为32位IP地址
- 函数inet_addr()将用户的点分十进制IP地址到32位IP地址的转换
- 函数gethosbyname()实现域名到32位IP地址转换(返回一个指向hostent结构的指针)
4)端口号
- 客户端还可能使用服务名(如HTTP)标志服务器端口
- 需要将服务名转化为熟知端口号(返回一个指向servent结构的指针)
5)解析协议号
- 客户端可能使用协议名(如:TCP)指定协议
- 需要将协议名转换为协议号(函数gethosbyname()实现协议名到协议号的转换;返回一个指向结构protent的指针)
6)TCP客户端软件流程
- 确定服务器IP地址和端口号
- 创建套接字
- 分配本地端点地址(IP地址+端口号)
- 连接服务器(套接字)
- 遵循应用层协议进行通信
- 关闭/释放连接
7)UDP客户端软件流程
- 确定服务器IO地址和端口号
- 创建套接字
- 分配本地端点地址(IP地址+端口号)
- 指定服务器端点地址,构造UDP数据报
- 遵循应用层协议进行通信
- 关闭/释放套接字