Winsock网络编程快速入门.docx

上传人:b****2 文档编号:25749611 上传时间:2023-06-12 格式:DOCX 页数:26 大小:27.08KB
下载 相关 举报
Winsock网络编程快速入门.docx_第1页
第1页 / 共26页
Winsock网络编程快速入门.docx_第2页
第2页 / 共26页
Winsock网络编程快速入门.docx_第3页
第3页 / 共26页
Winsock网络编程快速入门.docx_第4页
第4页 / 共26页
Winsock网络编程快速入门.docx_第5页
第5页 / 共26页
点击查看更多>>
下载资源
资源描述

Winsock网络编程快速入门.docx

《Winsock网络编程快速入门.docx》由会员分享,可在线阅读,更多相关《Winsock网络编程快速入门.docx(26页珍藏版)》请在冰豆网上搜索。

Winsock网络编程快速入门.docx

Winsock网络编程快速入门

TCP/IP五层模型的协议

应用层

传输层

网络层

数据链路层

物理层

物理层:

中继器、集线器、还有我们通常说的双绞线也工作在物理层,负责将比特流在结点间传输,即负责物理传输。

该层的协议既与链路有关也与传输介质有关。

链路层的任务是将整个帧从一个网络元素移动到邻近的网络元素,而物理层的任务是将该帧中的一个一个比特从一个节点移动到下一个节点。

该层中的协议仍然是链路相关的,并且进一步与链路(例如,双绞铜线、单模光纤)的实际传输媒体相关。

例如,以太网具有许多物理层协议:

关于双绞铜线的,关于同轴电缆的,关于光纤的,等等。

在每种情况下,跨越这些链路移动一个比特的方式不同。

数据链路层:

网桥(现已很少使用)、以太网交换机(二层交换机)、网卡(其实网卡是一半工作在物理层、一半工作在数据链路层),负责将IP数据报封装成合适在物理网络上传输的帧格式并传输,或将从物理网络接收到的帧解封,取出IP数据报交给网络层。

因特网的网络层通过一系列路由器在源和目的地之间发送分组。

为了将分组从一个节点(主机或路由器)移动到路径上的下一个节点,网络层必须依靠链路层的服务。

特别是在每个节点,网络层将数据报下传给链路层,链路层沿着路径将数据报传递给下一个节点。

在该下个节点,链路层将数据报上传给网络层。

网络层:

路由器、三层交换机等,责将数据报独立地从信源发送到信宿,主要解决路由选择、拥塞控制和网络互联等问题。

因特网的网络层负责将称为数据报(datagram)的网络层分组从一合主机移动到另一台主机。

源主机中的因特网传输层协议(TCP或UDP)向网络层递交运输层报文段和目的地址,就像你向邮政信件提供目的地址一样。

因特网的网络层包括著名的IP协议,该协议定义了数据报中的各个字段以及端系统和路由器如何作用于这些字段。

仅有一个IP协议,所有具有网络层的因特网组件都必须运行lP协议。

因特网的网络层也包括决定路由的选路协议,数据报根据该路由从源传输到目的地。

因特网是一个网络的网络,在一个网络中,其网络管理者能够运行所希望的任何选路协议。

尽管网络层包括了IP协议和一些选路协议,它经常只被称为IP层,这反映了IP是将因特网连接在一起的粘合剂这样一个事实。

传输层:

四层交换机、也有工作在四层的路由器,负责为信源和信宿提供应用程序进程间的数据传输服务,这一层上主要定义了两个传输协议,传输控制协议即TCP和用户数据报协议UDP。

运输层提供了在应用程序端点之间传送应用层报文的服务。

在因特网中,有两个运输层协议,即TCP和UDP,利用其中的任何一个都能传输应用层报文.TCP向它的应用程序提供了面向连接的服务。

这种服务包括了应用层报文向目的地的确保传递和流量控制(即发送方/接收方速率匹配)。

TCP也将长报文划分为短报文,并提供拥塞控制机制,因此当网络拥塞时,源抑制其传输速率。

UDP协议向它的应用程序提供无连接服务。

这是一种不提供不必要服务的服务,不提供可靠性,没有流量控制,也没有拥塞控制。

在本书中,我们将运输层分组称为报文段(segment)

应用层:

支持网络应用,应用协议仅仅是网络应用的一个组成部分,运行在不同主机上的进程则使用应用层协议进行通信。

主要的协议有:

http、ftp、telnet、smtp、pop3等。

应用层是网络应用程序及其应用层协议存留的地方。

因特网的应用层包括许多协议,例如HTTP(它为web文档提供了请求和传送)、SMTP(它提供了电子邮件报文的传输)和FTP(它提供了两个端系统之间的文件传送)。

我们将看到,某些网络功能,如将像www这样的对人友好的端系统名字转换为32比特网络地址,也是借助于应用层协议—域名系统(DNS)完成的。

应用层协议分布在多个端系统上,一个端系统中的应用程序使用协议与另一个端系统中的应用程序交换信息分组。

我们将这种位于应用层的信息分组称为报文(message)

TCP/UDP协议

TCP(TransmissionControlProtocol)和UDP(UserDatagramProtocol)协议属于传输层协议。

其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。

通过面向连接、端到端和可靠的数据包发送。

通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、流控或差错恢复功能。

一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。

TCP支持的应用协议主要有:

Telnet、FTP、SMTP等;UDP支持的应用层协议主要有:

NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等.

TCP/IP协议与低层的数据链路层和物理层无关,这也是TCP/IP的重要特点

一、基本知识

1、Winsock,一种标准API,一种网络编程接口,用于两个或多个应用程序(或进程)之间通过网络进行数据通信。

具有两个版本:

Winsock1:

WindowsCE平台支持。

头文件:

WinSock.h

库:

wsock32.lib

 

Winsock2:

部分平台如WindowsCE貌似不支持。

通过前缀WSA可以区别于Winsock1版本。

个别函数如WSAStartup、WSACleanup、WSARecvEx、WSAGetLastError都属于Winsock1.1规范的函数;

头文件:

WinSock2.h

库:

ws2_32.lib

 

mswsock.h用于编程扩展,使用时必须链接mswsock.dll。

 

2、网络协议:

IP(InternetProtocol) 网际协议,无连接协议;

TCP(TransmissionControlProtocol) 传输控制协议;

UDP(UserDatagramProtocol) 用户数据协议;

FTP(FileTransferProtocol) 文件传输协议;

HTTP(HypertextTransferProtocol) 超文本传输协议;

 

3、字节存储顺序:

big_endian:

大端存储,存储顺序从高位到低位,地址指向最高有效字节。

在网络中将IP和端口指定为多字节时使用大端存储,也称为网络字节顺序(network_byte)。

貌似MACOS使用的是大端存储方式;

 

little_endian:

小端存储,存储顺序从低位到高位,地址指向最低有效字节。

本地主机存储IP和端口制定的多字节时使用,也称为主机字节顺序(host_byte)。

大多数系统都是小端存储;

 

用下面的方式可以检测是否为大端存储:

boolIsBig_endian()

{

unsignedshorttest=0x1122;

if(*((unsignedchar*)&test)==0x11)

{

returntrue;

}

else

{

returnfalse;

}

}

此外有很多函数可以用来进行主机字节和网络字节之间的转换,如:

u_longhtonl(u_longhostlong);

intWSAHtonl(SOCKETs,u_longhostlong,u_longFAR*lpnetlong);

unsignedlonginet_addr(constcharFAR*cp);有时网络IP是点分法表示的,

如:

192.168.0.1,使用函数inet_addr可以将点分法的IP字符串作为一个网络字节顺序的32位u_long返回。

二、快速了解 

1、Winsock初始化:

首先确保包含对应版本的头文件,然后保证链接对应的库文件(可以在代码中使用#pragmacomment(lib,"WS2_32"),或在编译器项目属性中链接器->输入->附加依赖项中添加ws2_32.lib);

通过调用WSAStartup函数来实现加载Winsock库:

intWSAAPIWSAStartup(

INWORDwVersionRequested,

OUTLPWSADATAlpWSAData

);

其中参数wVersionRequested用来指定加载Winsock库的版本,y高位字节为次版本,x低位字节为主版本,使用宏MAKEWORD(x,y)来生成一个WORD;

参数lpWSAData是指向WSADATA结构指针,加载的版本库信息将会填充这个结构,详细内容自查。

在使用Winsock后需要释放资源,并取消应用程序挂起的Winsock操作。

使用intWASCleanup();

  

2、错误处理:

如果已经加载了Winsock库,则调用Winsock函数出错后,通常会返回SOCKET_ERROR,而通过使用函数intWSAGetLastError()可以获得具体信息值,例如:

.if(SOCKET_ERROR==WSACleanup())

{

cout<<"WSACleanuperror"<

return0;

}

根据获取错误信息值,可以知道错误原因,并进行相应的处理。

 

3、寻址:

想要进行通信就需要知道彼此的地址,一般来说这个地址由IP和端口号来决定。

在Winsock中使用SOCKADDR_IN结构来指定地址信息:

structsockaddr_in{

shortsin_family;

u_shortsin_port;

structin_addrsin_addr;

charsin_zero[8];

};

sin_family通常大多用的是都是AF_INET,代表TCP/IP协议族。

sin_port用于标示TCP或UDP通信端口,部分端口是为一些服务保留的,如FTP和HTTP使用要注意;必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字

sin_adr字段把地址(例如是IPv4地址)作为一个4字节的量来存储起来,它是u_long类型,且是网络字节顺序的。

可以使用inet_addr来处理点分法表示的IP地址,必要时可以用htonl()函数转换成网络数据格式的数字;

sin_zero只充当填充项,以使SOCKADDR_IN结构和SOCKADDR结构长度一样。

没有实际意义,只是为了跟SOCKADDR结构在内存中对齐

以下简单的使用SOCKADDR_IN来指定地址:

//创建一个地址

intserverPort=5150;

charFARserverIP[]="192.168.1.102";//本机ip,不知道就ipconfig

SOCKADDR_INserverAddr;

serverAddr.sin_family=AF_INET;

serverAddr.sin_port=htons(serverPort);//convertsau_shortfromhosttoTCP/IPnetwork

byteorder(whichisbig-endian).

serverAddr.sin_addr.s_addr=inet_addr(serverIP);

intserverAddr_size=static_cast(sizeof(serverAddr));

IN_ADDR结构:

TheIPaddresscomponentofthisstructureisoftypeIN_ADDR.TheIN_ADDRstructureisdefinedinWindowsSocketsheaderfileWINSOCK.Hasfollows:

struct  in_addr{

  union {

       struct{

           unsigned char  s_b1,//AnIPv4addressformattedasfouru_chars

                            s_b2,

                            s_b3,

                            s_b4;

      } S_un_b;

       struct {

     unsigned short s_w1,//AnIPv4addressformattedastwou_shorts.

              s_w2;

            } S_un_w;

unsignedlong S_addr;//AnIPv4addressformattedasau_long.

   }S_un;

};

以下例子来自于MSDN:

Thefollowingexampledemonstratestheuseofthesockaddrstructure.

//Declarevariables

SOCKETListenSocket;

Structsockaddr_insaServer;

hostent*localHost;

char*localIP;

//Createalisteningsocket,//创建socket

ListenSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

//Getthelocalhostinformation

localHost=gethostbyname("");//该函数可以从主机名数据库中得到对应的“主机”。

返回一个指向hostent结构的指针,它可以标识一个“主机”列表

localIP=inet_ntoa(*(structin_addr*)*localHost->h_addr_list);//convertsan(Ipv4)InternetnetworkaddressintoastringinInternetstandarddottedformat.

//Setupthesockaddrstructure

saServer.sin_family=AF_INET;

saServer.sin_addr.s_addr=inet_addr(localIP);//convertsastringcontainingan(Ipv4)InternetProtocoldottedaddressintoaproperaddress(unsignedlong)fortheIN_ADDRstructure

saServer.sin_port=htons(5150);//convertsau_shortfromhosttoTCP/IPnetworkbyteorder(whichisbig-endian).

//Bindthelisteningsocketusingthe

//informationinthesockaddrstructure

bind(ListenSocket,(SOCKADDR*)&saServer,sizeof(saServer));

有时作为一个连接通信的服务端来说,在设置监听socket的地址结构时sin_addr.s_addr的值可以是htonl(INADDR_ANY),INADDR_ANY允许将socket绑定到系统中所有可用的接口,以便传到任意接口的连接(端口必须正确)都可以被监听socket接受。

 

4、创建socket套接字:

套接字是通信时为传输提供的句柄,Winsock的操作都是基于套接字实现的。

创建一个套接字有socket和WSASocket方法:

SOCKETWSAAPIsocket(

INintaf,//协议的地址族,使用IPv4来描述Winsock,设置为AF_INET

INinttype,//套接字类型,TCP/IP设置为SOCK_STREAM,UDP/IP设置为SOCK_DGRAM

INintprotocol//用于给定地址族和类型具有多重入口的传送限定,TCP设置为IPPROTO_TCP,UDP设置为IPPROTO_UDP

);

如果创建成功,函数会返回一个有效的SOCKET,否则会返回INVALID_SOCKET,可以用WSAGetLastError()函数获得错误信息。

 

5、连接通信实现过程:

连结通信是基于TCP/IP实现的,进行数据传输前,通信双方要进行连接。

 

服务端:

初始化Winsock后,创建一个监听socket和一个要接受连接的地址结构;

使用bind将监听socket与地址结构进行关联;

intWSAAPIbind(INSOCKETs,//一个用于监听的socket

INconststructsockaddrFAR*name,//指向进行绑定的sockaddr地址结构

INintnamelen//进行绑定的sockaddr地址结构的大小

);

使用listen将bind成功的监听socket状态设置为监听状态;

intWSAAPIlisten(

INSOCKETs,//一个用于监听的socket,已经进行bind

INintbacklog//允许挂起连接的队列的最大长度,超过这个长度后,再有连接将会失败

);

使用accept接受通过监听socket获取的连接,成功后将返回的新的连接socket进行保存以便数据传输;

SOCKETWSAAPIaccept(

INSOCKETs,//处于监听模式的socket

OUTstructsockaddrFAR*addr,//指向一个地址结构,用来接收连接后获得对方地址信息

INOUTintFAR*addrlen//指向一个整数,表示参数2指向地址结构的大小

);

客户端:

初始化Winsock后,创建一个监听socket和一个要连接的服务器地址结构;

使用connect将socket和服务器地址结构进行初始化连接,成功后将使用socket进行数据传输;

intWSAAPIconnect(

INSOCKETs,//要建立连接的socket

INconststructsockaddrFAR*name,//指向保存要建立连接信息的地址结构

INintnamelen//参数2指向地址结构的大小

);

连接成功后,使用send、recv来进行数据传输;返回已经发送的数据长度

intWSAAPIsend(INSOCKETs,//进行连接的socket

INconstcharFAR*buf,//指向发送数据的缓冲区

INintlen,//发送数据的字符数

INintflags//一个标志位,可以是0、MSG_DONTROUTE、MSG_OOB还可以是他们的或运算结果

);

intWSAAPIrecv(

INSOCKETs,//进行连接的socket

OUTcharFAR*buf,//指向接受数据的缓冲区

INintlen,//准备接受数据字节数或缓冲区的长度

INintflags//可以是0、MSG_PEEK、MSG_OOB还可以是他们的或运算结果

);

连接结束后,使用shutdown和closesocket来断开连接和释放资源;

intWSAAPIshutdown(

INSOCKETs,//要关闭的socket

INinthow//关闭标志:

SD_RECEIVE、SD_SEND、SD_BOTH

);

6、无连接通信实现过程:

无连接通信是基于UDP/IP实现的,UDP不能确保可靠的数据传输,但能将数据发送到多个目标,或者接受多个源的数据。

初始化Winsock后,可以创建socket和用以进行通信任意地址结构;注意创建socket时type参数必须是SOCK_STREAM,protocol参数必须是IPPROTO_UDP。

//sendto和recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用.

使用recvfrom通过socket和通信的地址结构接受数据;

使用sendto通过socket和通信的地址结构发送数据;

intWSAAPIrecvfrom(INSOCKETs,

OUTcharFAR*buf,

INintlen,

INintflags,

OUTstructsockaddrFAR*from,

INOUTintFAR*fromlen

);

intWSAAPIsendto(INSOCKETs,

INconstcharFAR*buf,

INintlen,

INintflags,

INconststructsockaddrFAR*to,

INinttolen

);

同样通信结束后,使用shutdown和closesocket来断开连接和释放资源

 

 

上述使用函数都有多个版本,而且相关的一些标志位参数可以提供设置选项,另外,返回的错误处理等也有待于详细研究;

 

 

7、select函数:

select()用于确定一个或多个套接口的状态。

对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。

intWSAAPIselect(

INintnfds,//指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,在Windows中值无所谓。

INOUTfd_setFAR*readfds,//可选指针,指向一组等待可读性检查的套接字。

INOUTfd_setFAR*writefds,//可选指针,指向一组等待可写性检查的套接字。

INOUTfd_setFAR*exceptfds,//可选指针,指向一组等待错误检查的套接字。

INconststructtimevalFAR*timeout//select()最多等待时间,对阻塞操作则为NULL。

);

//用fd_set结构来表示一组等待检查的套接口。

在调用返回时,这个结构存有满足一定条件的套接口组的子集:

typedefstructfd_set{

u_intfd_count;//set元素数目

SOCKETfd_array[FD_SETSIZE];//保存

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 表格类模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1