windows网络编程的一些理论
参考自《VC++深入详解》
这是我在看书时记录下来的东西。
注:下面的Socket其实都应该是socket
第14章网络编程
Socket是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建,通过绑定与驱动程序建立关系。
此后,应用程序给Socket的数据,由Socket交给驱动程序向网络上发送出去。
计算机从网络上收到与该Socket绑定的IP地址和端口号相关的数据后,由驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据。
14.1 计算机网络基本知识。
1,最简单的网络形式是由两台计算机组成,就酱
2,网络上主机间通信需要知道另一主机的名字。在Internet上用一个称为IP地址(4个字节)的整数来标识网络设备。
在Internet上,两台主机要通信,双方必须遵守约定的规则,称为协议。
计算机中运行着很多网络通信程序(迅雷、酷狗、浏览器等),要怎么区分呢?端口号:标识在计算机上运行的每一个网络通信程序。所以,指定IP外,还要指定端口号。
IP地址相当于总机号码,而端口号相当于分机号码。
14.1.1 IP地址
IP网络中每台主机必须有唯一的IP地址
IP地址是一个逻辑地址
因特网上的IP地址具有全球唯一性
32位,4字节。常用点分十进制表示,例如:192.168.0.1(每个字节用十进制整数来表示)
注:127.0.0.1 称为是回送地址,指本地机,一般用来测试使用
14.1.2 协议 P533
为进行网络中的数据交换而建立的规则,标准或约定
不同层具有各自不同的协议。
14.1.5 ISO/OSI 七层参考模型
1,ISO国际标准化组织提出来OSI七层参考模型,将网络的不同功能划分为7层。如下图
从低到高各层的功能分别如下所述:
(1) 物理层:提供二进制传输,确定在通信信道上如何传输比特流
(2) 数据链路层:提供介质访问,加强物理层的传输功能,建立一条无差错的传输线路
(3) 网络层:提供IP寻址和路由。因为在网络上数据可以经由多条线路到达目的地,网络层负责找出最佳的传输线路
(4) 传输层:为源主机到目的端主机提供可靠的数据传输服务,隔离网络的上下层协议,使得网络应用与下层协议无关
(5) 会话层:在两个相互通信的应用程序之间建立、组织和协调其相互之间的通信
(6) 表示层:处理被传送数据的表示问题,即信息的语法和语义。如有必要,可使用一种通用的数据表示格式,在多种数据表示之间进行切换。
(7) 应用层:为用户的网络应用程序提供网络通信的服务
应注意一下几点:
(1) OSI七层参考模型并不是物理实体存在这七层,这只是一个功能的划分,是一个抽象的网络参考模型
(2) 在进行一个网络通信时,每一层为本次通信提供本层的服务。通信实体的对等层之间不允许直接通信
(3) 各层之间是严格单向依赖
(4) 上层使用下层提供的服务 – Service user
(5) 下层向上层提供服务 – Service provider
2,通信时数据传输的过程:在两个通信实体进行通信时,应用层所发出的数据经过表示层、会话层、传输层、网络层、数据链路层、最终到达物理层,在该层通过物理线路传输给另外一个实体的物理层。
然后,数据再依次向上传递,传递给另一个实体的应用层。
3,对等层通信的实质就是: 对等层实体之间虚拟通信。下层向上层提供服务,实际通信在最底层完成。
4,OSI7层参考模型中的应用层、传输层和网络层所用的协议:
(1) 应用层:远程登录协议Telnet,文件传输协议FTP(下载文件),超文本传输协议HTTP(浏览网页),
域名服务DNS(网址就是域名),简单邮件传输协议SMTP(发送邮件),邮局协议POP3(收取邮件)。
(2) 传输层:传输控制协议TCP:面向连接的可靠的传输协议,通信时要通过三步握手以建立通信双方的连接。
用户数据报协议UDP:无连接、不可靠的传输协议。不需要建立连接,可能会丢失数据,实时性较高。
(3) 网络层:网络协议IP、Internet互联网控制报文协议ICMP,Internet组管理协议IGMP。
14.1.6 数据封装
1,往另外一台计算机发送数据,首先要将该数据打包打包的过程称为封装。
2,封装就是在数据前面加上特定的协议头部,例如:用TCP协议传时,数据到传输层时,就会加上TCP协议头,在到达网络层时,在其前面加上IP协议头。
3,OSI参考模型中,对等协议之间交换的信息单元统称为协议数据单元(PDU)。
4,为了提供服务,下层把上层的PDU作为本层的数据封装,然后加入本层的头部(有点还要加尾部,如数据链路层)。头部的数据中含有数据传输所需的控制信息。
14.1.7 TCP/IP模型
1,起源于美国国防部高级研究规划署的一项研究计划,现在。已经称为Internet上通信的工业标准。
2,OSI参考模型比较复杂,目前应用较多的是TCP/IP模型,该模型包含4个层次: 应用层 传输层 网络层 网络接口层
14.1.8 端口
1,端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序通过系统调用与某端口建立连接(binding)后,传输层传给该端口的数据都被相应的进程所接收。
相应进程发给传输层的数据都通过该端口输出。
2,端口用一个整数型标识符来表示,即端口号。(0 – 65535,我们在编写网络应用程序时,要为程序指定1024以上的端口号)。
3,端口号跟协议相关,TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立。
也就是说基于TCP和UDP协议的不同的网络应用程序,它们可以拥有相同的端口号。
14.1.9 套接字的引入
1,伯克利大学推出一种应用程序访问通信协议的操作系统调用套接字。Socket的出现,使程序员可以很方便的访问TCP/IP,从而开发各种网络应用的程序。
2,套接字存在于通信区域中。通信区域也叫地址族,是一个抽象的概念,主要用于将通过套接字通信的进程的共有特性综合在一起。套接字通常只于同一区域的套接字交换数据。
Windows Socket只支持一个通信区域:网际域(AF_INET),这个域被使用网际协议簇通信的进程使用。
14.1.10 网络字节顺序
1,小端模式:低位存在低地址。(低位先存)
2,大端模式:高位存在低地址。(高位先存)
3,基于Inter的CPU,我们常用的PC机采用的是小端模式,为了保证数据的正确性,在网络协议中需要指定网络字节顺序。
4,TCP/IP协议使用16位整数和32位整数的高位先存格式(大端模式)。
5,在网络中不同主机间进行通信时,要统一采用网络字节顺序。
14.1.11 客户机/服务器模式(C/S)
1,在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式(客户向服务器提出请求,服务器收到请求后,提供相应的服务)。
2,客户机/服务器模式在操作过程中采取的是主动请求的方式。
首先服务器方要先启动,并根据请求提供相应的服务:
(1) 打开一个通信通道并告知本地主机,它愿意在某一地址和端口上接收客户请求。
(2) 等待客户请求到达该端口
(3) 接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,要激活一个新的进程(或线程)来处理这个客户请求。
新进程(线程)处理此客户请求,并不需要对其他请求做出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4) 返回第二步
(5) 关闭服务器
而客户方:
(1) 打开一个通信通道,并连接到服务器所在主机的特定端口。
(2) 向服务器发送服务请求报文,等待并接收应答:继续提出请求,
(3) 请求结束后关闭通信通道并终止。
14.2 Windows Socket的实现
14.2.1 套接字的类型:
(1)流式套接字(SOCK_STREAM):提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按照发送顺序接收。基于TCP协议实现的
(2)数据报套接字(SOCK_DGRAM):提供无连接服务,数据包以独立包形式发送,不提供无错保证,数据可能丢失或重复,接收顺序混乱。基于UDP协议实现的
(3)原始套接字(SOCK_RAW)
14.2.2 基于TCP的Socket编程
服务器端程序流程如下:
(1) 创建套接字(socket)
(2) 将套接字绑定到一个本地地址和端口上(bind)
(3) 将套接字设为监听模式,准备接收客户请求(listen)
(4) 等待客户机请求到来:当请求到来时,接收连接请求,返回一个新的对应于此次连接的套接字(accept)】
(5) 用返回的套接字和客户端进行通信(send/recv)
(6) 返回,等待另一个客户请求
(7) 关闭套接字
客户端程序流程如下:
(1) 创建套接字(socket)
(2) 向服务器发出连接请求(connect)
(3) 和服务器端进行通信(send/recv)
(4) 关闭套接字
服务器端,调用accept函数时,程序就会等待,等待客户端调用connect函数发出连接请求,然后服务器接收该请求,于是双方就建立了连接。
之后,服务器和客户端就可以通过recv/send进行通信了
客户端不要调用bind,因为服务器需要接收客户端的请求,所以必须告诉本地主机打算在哪个IP地址和哪个端口上等待客户请求,因此必须调用bind来实现这一功能。
客户端发起连接,服务器接收该请求后,在服务器就保存了客户端的IP地址和端口的信息,这样就可以利用所返回的套接字调用recv/send函数与客户端进行通信了。
14.2.3 基于UDP(面向无连接的)socket编程
1,服务器端也叫接收端,先启动的一端称为接收端,发送数据的一段称为发送端,也称客户端。(这个概念好像和Linux的有点不一样)
接收端程序的编写:
(1) 创建套接字(socket)
(2) 将套接字绑定到一个本地地址和端口上(bind)
(3) 等待接收数据(recvfrom) // 不是recv linux这里也可以发送数据
(4) 关闭套接字
客户端程序的编写:
(1) 创建套接字(socket)
(2) 向服务器发送数据(sendto) // 不是send
(3) 关闭套接字
套接字相当于电话机,IP地址相当于总机号码,端口相当于分机
14.3 相关函数
14.3.1 WSAStartup函数(加载套接字库)
1,利用套接字编程时,第一步要加载套接字库。这个函数有两个功能:
(1) 加载套接字库
(2) 进行套接字库的版本协商,就是确定将使用的socket版本
2,每个WSAStartup成功调用(成功加载winsock动态库以后),在最后都会对应一个WSACleanUp调用,以便释放为该应用分配的资源。
终止对Winsock动态库的使用。
14.3.2 socket函数:加载库之后,用这个函数创建套接字了
1,原型声明如下啊:
14.3.3 bind函数:创建套接字以后,要将该套接字绑定到本地的某个地址和端口上
1,原型
Int bind(SOCKET s, const struct socketaddr FAR *name, int namelen);
成功返回0,失败返回一个SOCKET_ERROR,错误信息可以在WSAGetLastError函数返回。
s :指定要绑定的套接字
name :指定了该套接字的本地地址信息,由于该地址结构是为所有的地址家族准备的,这个结构可能随所使用的网络协议不同而不同
namelen :指定该地址结构的长度
2,sockaddr结构
struct socketaddr
{
u_short sa_family; // 指定地址家族,对于TCP/IP协议的套接字,必须设置为 AF_INET
char sa_data[14]; // 仅仅表示要求一块内存分配区,起到占位的作用
};
3,在基于TCP/IP的socket编程过程中,可以用sockaddr_in结构替换sockaddr
struct socketaddr_in
{
short sin_family; // 地址族,对于IP地址,这个值一直是 AF_INET
unsigned short sin_port; // 指定将要分配给套接字的端口
struct in_addr sin_addr; // 套接字的主机IP地址
char sin_zero[8];// 填充数
};
4,sockaddr_in结构中的sin_addr成员类型是in_addr,这个实际上是一个联合(union),
通常利用这个结构将一个点分十进制格式的IP地址转换为u_long类型。
14.3.4 inet_addr和inet_ntoa函数
1,将IP地址指定为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接收数据。
2,每个机器只有一个IP,但有的机器有多个网卡,每个网卡都会有自己的IP地址。
3,如果想让套接字使用多个IP中的一个地址,就必须指定实际地址,可以用inet_addr函数来实现。
4,unsigned long inet_addr(const char FAR *cp);
Cp:指定了以点分十进制格式表示的IP地址
5,char FAR *inet_ntoa(struct in_addr in);
这个函数会完成相反的转换,接收一个in_addr结构体类型的参数并返回一个以点分十进制表示的IP地址字符串
14.3.5 listen函数:将指定的套接字设置为监听模式
1,int listen(SOCKET s, int backlog);
s:套接字描述符
backlog:等待连接队列的最大长度
2,backlog是为了设置等待连接队列的最大长度,不是在一个端口上同时可以进行连接的数目。
(假如设为2,有3个请求同时来的时候,前两个会放到等待请求连接队列中,然后由应用程序一次为这些请求服务,第三个连接请求被拒绝了)
14.3.6 accept函数:接收客户端发送的连接请求
1,SOCKET accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);
s:套接字描述符,这个套接字已经设置为监听状态
addr:指向一个缓冲区的指针,用来接收连接实体的地址(客户端连接时,保存这个客户端的Ip地址信息和端口信息)
addrlen:也是返回参数,返回包含地址信息的长度
14.3.7 send函数:向一个已经建立连接的套接字发送数据
1, int send(SOCKET s, const char FAR *buf, int len, int flags);
s:已经建立连接的套接字
buf:指向一个缓冲区,包含将要传递的数据
len:缓冲区的长度
flags:这个值将影响函数的行为,一般设为0
14.3.8 recv函数:从一个已连接的套接字接收数据
1, int recv(SOCKET s, const char FAR *buf, int len, int flags);
s:已经建立连接的套接字
buf:指向一个缓冲区,保存接收的数据
len:缓冲区的长度
flags:这个值将影响函数的行为,一般设为0
14.3.9 connect:与一个特定的套接字建立连接(客户端连接服务器)
Int connect(SOCKET s, const struct socketaddr FAR *name, int namelen);
s:即将在其上就建立连接是那个套接字
name:设定连接的服务器端地址信息
namelen:指定服务器端地址长度
14.3.10 recvfrom:接收一个数据报信息并保存源地址
1,int recvfrom(
SOCKET s, // 准备接收数据的套接字
char FAR* buf, // 指向一个缓冲区的指针,用来接收数据
int len, // 缓冲区的长度
int flags, // 与send函数的第四个参数类似
struct sockaddr FAR* from, // 接收发送数据方的地址信息
int FAR* fromlen // 输入输出参数,函数调用之后,会通过这个参数返回一个值,该返回值是地址结构的大小
);
14.3.11 sendto:向一个特定的目的方发送数据
1,int sendto(
SOCKET s, // 一个套接字描述符(可能已经建立连接)
char FAR* buf, // 指向一个缓冲区的指针,包含将要发送的数据
int len, // 缓冲区的长度
int flags, // 与send函数的第四个参数类似
struct sockaddr FAR* to, // 可选的指针,指定目标套接字的地址
int FAR* tolen // 参数to中指定的地址的长度
);
14.3.12 htons和htonl函数
1,u_shorts htons(u_short hostshort); // 把一个u_short类型的值从主机字节顺序转换成TCP/IP网络字节顺序
参数:一个以主机字节顺序表示的16位数值
2,u_long htonl(u_long hostshort); // 把一个u_long类型的值从主机字节顺序转换成TCP/IP网络字节顺序
参数:一个以主机字节顺序表示的32位数值
注意:当链接不到这个库的时候,可以这样进行显示加载(这个是我测试时遇到的问题)
#include<Winsock2.h>
// 显示加载这个库WS2_32.DLL
#pragma comment(lib, "WS2_32");
windows网络编程的一些理论的更多相关文章
- [转]Windows网络编程学习-面向连接的编程方式
直接附上原文链接:windows 网络编程学习-面向连接的编程方式
- Windows网络编程 2 【转】
Windows网络编程使用winsock.Winsock是一个基于Socket模型的API,在Windows系统中广泛使用.使用Winsock进行网络编程需要包含头文件Winsock2.h,需要使用库 ...
- 不为人知的网络编程(九):理论联系实际,全方位深入理解DNS
本文原作者:selfboot,博客地址:selfboot.cn,Github地址:github.com/selfboot,感谢原作者的技术分享. 1.引言 对于 DNS(Domain Name Sys ...
- Windows 网络编程
网络编程 API ,失败返回 -,错误代码 WSASYSNOTREADY 表示基础网络子系统没有准备好网络通行,WSAVERNOTSUPPORTED 表示 Socket 版本不支持,WSAEINPRO ...
- Windows网络编程(C/C++服务器编程)
Windows服务器网络编程 Linux服务器网络编程
- windows 网络编程[转]
利用winsock编写网络应用程序服务端的步骤简述如下WSAStartup 初始化网络编程库 socket 创建套接字 bind 指定地址.端口,绑定套接字 listen 进入监听状态 accept ...
- Windows网络编程笔记4 -- Winsock 协议相关知识
Win32平台上的Winsock编程,Winsock是一个与协议无关的接口.以下协议是我们需要了解的: 网络协议的特征包括: 1. 面向消息 2. 面向连接和无线接 3. 可靠性和次序性 4. ...
- Windows网络编程笔记1
第一部分 传统网络API 传统的网络接口NetBIOS.重定向器.邮槽.命名管道等.第一,NetBIOS(Network Basic Input/Output System, NetBIOS)“网络基 ...
- windows网络编程-2015.12.29
在windows环境下,使用netstat命令查看网络状态,具体命令如下所示: netstat -ano | findstr listenport 在windows环境下,创建udp程序接收端,具体代 ...
随机推荐
- 关于php中的spl_autoload_register
一.自动加载定义 很多开发者写面向对象的应用程序时对每个类的定义建立一个 PHP 源文件.一个很大的烦恼是不得不在每个脚本开头写一个长长的包含文件列表(每个类一个文件). 在 PHP 5 中,不再需要 ...
- 在SQL2008R2查询分析器出错(在执行批处理时出现错误。错误消息为: 目录名称无效。)
在用SQL2008R2查询分析器时 SELECT * FROM 表名; 出错: 在执行批处理时出现错误.错误消息为: 目录名称无效. 原因: 在打开查询分析器时,用360软件清空了临时文件(只是偶尔1 ...
- SQL2012数据库加密方法
1.非对称密钥来保护新的对称密钥 /*--测试环境 Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64) Oct 19 2012 13:38:57 C ...
- solr 导入数据
从sqlserver导入数据到solr, solr 采用的版本6.0.1,并且本机解压到:F:\Tool\solr-6.0.1: 1. 命令启动solr,创建core 启动,进入solr文件目录下,执 ...
- centos7 + php7 lamp全套最新版本配置,还有mongodb和redis
我是个懒人,能yum就yum啦 所有软件的版本一直会升级,注意自己当时的版本是不是已经更新了. 首先装centos7 如果你忘了设置swap分区,下面的文章可以教你怎么补一个上去: http://ww ...
- esxi安装全过程及基本配置
esxi6.0下载地址 链接: http://pan.baidu.com/s/1jIfg2yU 密码: qacv 支持检测可以参考:http://www.linuxidc.com/Linux/2012 ...
- 记一次Web应用CPU偏高
LZ开发的一个公司内部应用供查询HIVE数据使用.部署上线后总是会出现CPU偏高的情况,而且本地测试很难重现.之前出现几次都是通过直接重启后继续使用,因为是内部使用,重启一下也没有很大影响(当然,每次 ...
- Linux Strip
一.简介 strip经常用来去除目标文件中的一些符号表.调试符号表信息,以减小程序的大小. 二.语法 https://sourceware.org/binutils/docs/binutils/str ...
- 笔者的编辑语法:MarkDown
由于博客园里的文章有很多排版不好,一大堆文字堆在一块会影响到阅读. MarkDowm:百科 Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber).它允许人们“使用易读 ...
- html,datepicker,datetimepicker时间控件使用
1.My97DatePicker 传送门:点击打开链接 ps:My97DatePicker貌似对chrom不兼容 2.jquery日期选择/日历 http://www.oschina.net/proj ...