vlambda博客
学习文章列表

C语言高级编程——网络编程技术

了解什么是网络编程

熟悉七层网络模型

熟悉网络开发中使用到的函数

掌握TCP协议类程序开发

掌握UDP协议类程序开发

计算机本身是不会进行网络通信的,所以要想使通过软件进行网络通信,必须制定相应的规则,其中就包括网络架构、通讯协议、等等。

端口,一个主机中可能会有很多网络通信程序,每一个程序都要使用这个固定ip进行通信,所以端口就是每一个固定程序的id。

TCP (流格式传输控制协议)

UDP(数据包格式传输控制协议)

网络架构

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。在因特网协议族中,TCP层是位于IP层之上,应用层之下的中间层。

UDP是User Datagram Protocol的简称,中文名是用户数据报协议,是OSI参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。

七层网络架构组成:

应用层(Application)

表示层(Presentation) 

会话层(Session)

传输层(Transport)

网络层(Network)

数据链路层(Data Link)

物理层(Physical)

物理层是硬件。应用层是和硬件层相隔最远的--它是用户和网络交互的地方。

首先是简单的一个:socket描述符。它是下面的类型:int,仅仅是一个常见的int。

需要注意的是:有两种字节排列顺序:重要的字节在前面,或者不重要的字节在前面。前一种叫“网络字节顺序(Network Byte Order)”。有些机器在内部是按照这个顺序储存数据,而另外一些则不然。当要求某数据必须按照NBO顺序,那么就要调用函数(例如htons())来将它从本机字节顺序(Host Byte Order)转换过来。如果没有用到NBO,那么就让它保持本机字节顺序。

网络字节顺序NBO:按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。

主机字节顺序HBO:不同的机器HBO不相同,与CPU设计有关,不同的CPU有不同的字节序类型。这些字节序是指整数在内存中保存的顺序,这个叫做主机序。

socket函数

bind函数

connect函数

listen函数

accept函数

WSAStartup函数与WSACleanup函数

send函数与recv函数

sendto函数与recvfrom函数

closesocket函数与shutdown函数

       SOCKET socket ( 

        int af,       

        int type,     

        int protocol    );

参数介绍如下:

type:新套接口的类型描述。

protocol:套接口所用的协议。如调用者不想指定,可用0指定,表示缺省。

在使用socket函数进行编程时,需要加入winsock2.h头文件,并且引入ws2_32.lib静态库。

函数原型:

int bind

(     SOCKET s,

            const struct sockaddr FAR*  name,

            int namelen     );

参数类型:

s:已经创建好的一个套接字句柄。

name:是一个指向sockaddr结构体类型的指针。

namelen:表示sockaddr结构的长度,可以用sizeof函数获得。

本函数用于创建与指定外部端口的连接。s参数指定一个未连接的数据报或流类套接口。如套接口未被捆绑,则系统赋给本地关联一个唯一的值,且设置套接口为已捆绑。

函数原型:

      int connect (

          SOCKET s,                          

          const struct sockaddr FAR*  name,  

          int namelen                        

      );

参数类型:

s:标识一个未连接socket

name:指向要连接套接字的sockaddr结构体的指针

namelen:sockaddr结构体的字节长度

Listen函数让创建的套接字处于监听状态,主要用于监听连接请求。

函数原型:

int listen (

  SOCKET s,

  int backlog

);

参数说明:

s一个已绑定未被连接的套接字描述符

backlog连接请求队列的最大长度(一般由2到4)

accept函数主要用于服务器端,一般位于listen函数之后,默认会阻塞进程,直到有一个客户请求连接,建立好连接后,它返回的一个新的套接字socket_new,此后,服务器端即可使用这个新的套接字socket_new与该客户端进行通信,而sock则继续用于监听其他客户端的连接请求。

函数原型:

SOCKET accept (

  SOCKET s,

  struct sockaddr FAR* addr,

  int FAR* addrlen

);

参数说明:

s:套接字句柄,该套接口在listen()后监听连接。

WSAStartup函数完成对Winsock服务的初始化,使用Socket的程序在使用Socket之前必须调用WSAStartup函数。该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;操作系统利用第二个参数返回请求的Socket的版本信息。

WSACleanup函数用于清理工作,每一次WSAStartup()调用,必须有一个WSACleanup()调用,用于实际的清理工作。此函数没有参数因为它只做清理工作

send函数适用于已连接的数据包或流式套接口发送数据。对于数据报类套接口,必需注意发送数据长度不应超过通讯子网的IP包最大长度。

recv函数同send函数类似,只不过一个用于发送一个用于接收。

Sendto函数用来将数据由指定的socket传给对方主机,由于sendto函数是基于UDP传输协议的所以不用建立连接。

Closesocket函数关闭一个已经建立的套接字。更确切地说,它释放socket建立好的套接字句柄,关闭以后对对套接字的访问均以WSAENOTSOCK错误返回。

shutdown函数用于任何类型的套接口禁止接收、禁止发送或禁止收发。

基于TCP协议的网络通信程序,有一个服务端一个客户端,查看一下一个简单通讯模型。

Tcp通信基本流程:

服务器端-----------------------------------------------客户端

1.创建socket------------------------------------------1.创建socket

2.bind()

3.listen()

4.accept()

等待客户端连接---------------------------------------2.connect()

5.读数据(recv)-------------------------------------3.写数据(send)

6.写数据(send)------------------------------------4.读数据(recv)

7.关闭socket(closesocket())---------------5.关闭socket(closesocket())

基于UDP协议我们做一个聊天室程序,它分为服务端和客户端两个程序。

Udp通信基本流程:

服务器端:-------------------------------------客户端

1.创建socket----------------------------------1.创建socket

2.bind()-------------------------------------2.bind()

3.recvfrom

等待连接---------------------------------------3.sendto()

4.sendto()--------------------------------- 4.recvfrom()

5.关闭socket(closesocket())------5.关闭socket(closesocket())