基于TCP与UDP的windows网络编程

一、网络字节顺序与主机字节顺序

不同的计算机存放多字节值的顺序不同,有的机器在起始地址存放低位字节(低位先存),有的机器在起始地址存放高位字节(高位先存)。基于 Inter 的 CPU ,即使我们常用的 PC 机采用的是低位先存。为保证数据的正确性,在网络协议中需要指定网络字节顺序, TCP/IP 协议使用16位整数和32位整数的高位先存格式。由于不同计算机存放数据字节的顺序不同,这样发送数据后,即使接收方接收到该数据,也有可能无法查看所接收到的数据。所以在网络中不同主机间进行通讯时,要统一采用网络字节顺序。

下面是 WinSockAPI 提供的几个转换函数:

u_long htonl(u_long hostlong);//将32位的主机字节序转换为32位的网络字节序,htonl => host to net long

u_short htons(u_short hostshort);//将16位的主机字节序转换为16位的网络字节序,htons => host to net short

u_long ntohl(u_long netlong);//将32位的网络字节序转换为32位的主机字节序,ntohl => net to host long

u_short ntohs(u_short netshort);//将16位的网络字节序转换为16位的主机字节序,ntohs => net to host short

二、套接字(socket)的类型

  • 流式套接字(SOCK_STREAM)
    提供面向连接,可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。流式套接字实际上是基于 TCP 协议实现的。

  • 数据报套接字(SOCK_DGRAM)
    提供无连接服务。数据包以独立包形式发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。数据报式套接字实际上是基于 UDP 协议实现的。

  • 原始套接字(SOCK_RAW)
    原始套接字可以读写内核没有处理的 IP 数据包,而流套接字只能读取 TCP 协议的数据,数据报套接字只能读取 UDP 协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

三、基于TCP(面向连接)的 socket 编程

基于 TCP(面向连接)的 socket 编程的服务器端程序流程如下:

  1. 创建一个套接字(socket)。
  2. 将套接字绑定到一个本地地址和端口上(bind)。
  3. 将套接字设置为监听模式,准备接收客户的请求(listen)。
  4. 等待客户请求的到来;当请求到来后,接受连接请求,返回一个新的对应与此连接的套接字(accept)。
  5. 用返回的套接字和客户端进行通信(send/recv)。
  6. 返回,等待另一客户请求。
  7. 关闭套接字。

基于TPC(面向连接)的 socket 编程的客户端程序流程如下:

  1. 创建套接字(socket)。
  2. 向服务器发出连接请求(connect)。
  3. 和服务器端进行通信(send/recv)。
  4. 关闭套接字。

在服务器端,当调用 accept 函数时,程序就会等待,等待客户调用 connect 函数发出连接请求,然后服务器端接受该请求,于是双方就建立了连接。之后,服务器端和客户端就可以利用 send 和 recv 函数进行通信了。注意,在客户端不需要调用 bind 函数。因为服务器需要接收客户端的请求,所以必须告诉本地主机它打算在哪个 IP 地址和哪个端口上等待客户请求,因此必须调用 bind 函数来实现这一功能。而对客户端来说,当它发起连接请求,服务器接受该请求后,在服务器端就已经保存了该客户端的 IP 地址和端口号的信息。这样,对服务器端来说,一旦建立连接后,实际上已经保存了客户端的 IP 地址和端口号信息,因此就可以利用返回的套接字调用 send/recv 函数与客户端进行通信。

四、基于UDP(面向无连接)的 socket 编程

服务器端也叫做接收端,对于 UDP 的套接字来说,它的服务器端和客户端这种概念不是很强化,我们也可以把服务器端,即先启动的一端称为接收端,发送数据的一端称为客户端。

接收端程序的编写:

  1. 创建套接字(socket)。
  2. 将套接字绑定到一个本地地址和端口上(bind)。
  3. 等待接收数据(recvfrom)。
  4. 关闭套接字。

对于基于 UDP 的套接字编程,为什么仍要需要调用 bind 函数进行绑定呢?应注意,虽然面向无连接的 socket 编程无须建立连接,但是为了完成这次通信,对于接收端来说,它必须先启动以接收客户端发送的数据,因此接收端必须告诉主机它在哪个地址和端口等待数据的到来,也就是说,接收端必须调用 bind 函数将套接字绑定到一个本地地址和端口上。

客户端程序的编写:

  1. 创建套接字(socket)。
  2. 向服务器发送数据(sendto)。
  3. 关闭套接字。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章