1.基本概念

网络程序和普通程序最大的区别是,网络程序是由两个部分组成的,即客户端和服客户端的由务器端。网络程序是先服务器程序启动,等待客户端的程序运行并建立连接,一般来说,服务器的程序在一个端口上监听,直到有一个客户端的程序发来请求。

1.1 OSI模型

OSI模型是国际互联网标准化组织所定义的,目的是为了使网络的各个层次有标准。

OSI模型共7个层次:

(1)物理层:硬件连接的接口

(2)数据链路层:负责实现通信信道的无差错传输,提供数据帧、差错控制、流量控制和链路控制等功能。

(3)网络层:负责将数据正确迅速地从源主机传送到目的主机,其功能主要有寻址以及相关的流量控制和拥塞控制等。

(4)传输层:为上层处理过程掩盖下层结构的细节,保证把会话层的信息有效地传输到另一方的会话层

(5)会话层:提供服务请求者和提供者之间的通信,用以实现两端主机之间的会话管理、传输同步和活动管理等

(6)表示层:主要功能是实现信息转换

(7)应用层:为用户提供常用的应用

1.2 常用命令
  • netstat

    命令netstat用于网络的连接、路由器和接口统计等网络的信息

    常用命令:netstat -an:用于显示详细的网络状态

  • telnet

    命令telnet是用来远程控制的程序,可以用该程序来调试用户的服务端程序

1.3 网络地址

网络地址是终端在整个网络中的唯一标识,

1.4 IP设置项
  • IP地址:机器的唯一识别的网络地址
  • 网络广播地址
  • 子网掩码:用于——屏蔽IP网络的一部分、区分网络标识和主机标识、识别子网
  • 网关:用于访问外网
  • MAC地址:网卡的物理地址
1.5 端口

网络地址用来识别哪一台机器;端口用于识别一台机器的哪一个程序

端口分类:

  • 公认端口:端口号为0~1023
  • 注册端口:端口号为1024~49151
  • 动态端口:端口号为49152~65535

2.TCP/IP协议

TCP/IP:传输控制协议/因特网互联协议,又叫网络通信协议

2.1 整体架构概述

TCP/IP 实际上一个协同工作的通信家族,为网络数据通信提供通路。为讨论方便可TCP/IP 协议组大体上分为三部分:

  • Internet 协议(IP)
  • 传输控制协议(TCP)和用户数据报协议(UDP)
  • 处于 TCP 和 UDP 之上的一组应用协议。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等

在这里插入图片描述

2.2 IP协议

IP主要有以下四个主要功能:

  • 数据传送
  • 寻址
  • 路由选择
  • 数据报文的分段

IP的主要目的

为数据输入/输出网络提供基本算法,为高层协议提供无连接的传送服务。

2.3 IP构成

IP包由IP协议头与协议数据两部分构成。

2.4 TCP协议

TCP是重要的传输层协议,目的是允许数据同网络上的其他节点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输

TCP 协议具有严格的内装差错检验算法确保数据的完整性。
TCP 是面向字节的顺序协议,这意味着包内的每个字节被分配一个顺序编号,并分配给每包一个顺序编号。

基于TCP连接的建立
在这里插入图片描述

2.5 UDP协议

UDP也是传输层协议,它是无连接的,不可靠的传输服务。

当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文。
由于它执行功能时具有较低的开销,因而执行速度比TCP快。

基于UDP协议连接的建立

3.Linux网络编程

Linux中的网络编程通过Socket(套接字)接口实现,Socket是一种文件描述符

3.1 类型

套接字socket有三种类型:

  • 流式套接字(SOCK_STREAM)

流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP 保证了数据传输的正确性和顺序性

  • 数据报套接字(SOCK_DGRAM)

数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的 ,并且不保证可靠,无差错,它使用数据报协议UDP。

  • 原始套接字

原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议的测试等

3.2 函数使用

进行Socket编程

常用函数:

  • socket()

创建一个socket(套接字)。

  • bind()

用于绑定IP地址和端口号到socket。

  • connect()

该函数用于绑定之后的client端,与服务器建立连接。

操作函数:

  • listen()

设置能处理的最大连接要求,Listen()并未开始接收连线,只是设置socket为listen模式。

  • accept()

用来接受socket连接。

  • Send()

发送数据

  • Recv()

接收数据

4.服务器模型

在网络程序里面,一般来说都是许多客户对应一个服务器,为了处理客户的请求, 对服务端的程序就提出了特殊的要求。目前最常用的服务器模型有:

  • 循环服务器:服务器在同一个时刻只可以响应一个客户端的请求
  • 并发服务器:服务器在同一个时刻可以响应多个客户端的请求
4.1 UDP循环服务器

UDP循环服务器的实现方法:
UDP服务器每次从套接字上读取一个客户端的请求->处理->然后将结果返回给客户机。

socket(...); 
bind(...);
while(1)
{
	recvfrom(...); 
	process(...);
	sendto(...);
}

因为UDP是非面向连接的,没有一个客户端可以老是占住服务端, 服务器对于每一个客户机的请求总是能够满足。

4.2 TCP循环服务器

TCP服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。算法如下:

socket(...);
bind(...);
listen(...);
while(1)
{ 
	accept(...);
	process(...);
	close(...);
} 

TCP循环服务器一次只能处理一个客户端的请求。只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求。这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了,因此,TCP服务器一般很少用循环服务器模型的。

4.3 TCP并发服务器

并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是由服务器创建一个 子进程来处理。算法如下:

socket(...);
bind(...);
listen(...);
while(1)
{
	accept(...);
	if(fork(..)==0)
	{
		process(...);
		close(...);
		exit(...);
	}
	close(...);
} 

TCP并发服务器可以解决TCP循环服务器客户机独占服务器的情况。但同时也带来了问题:为了响应客户的请求,服务器要创建子进程来处理,而创建子进程是一种非常消耗资源的操作。

5.多路复用IO

1.设置要监控的文件

2.调用Select开始监控

3.判断文件是否发生变化

阻塞函数在完成其指定的任务以前不允许程序继续向下执行。

例如:当服务器运行到accept语句时,而没有客户请求连接,服务器就会停止在accept语句上等待连接请求的到来。这种情况称为阻塞(blocking)

而非阻塞操作则可以立即完成。

例如,如果你希望服务器仅仅检查是否有客户在等待连接,有就接受连接,否则就继续做其他事情,则可以通过使用select系统调用来实现。
除此之外,select还可以同时监视多个套接字 。

int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct timeval *timeout)
  • Maxfd: 文件描述符的范围,比待检的最大文件描述符大1
  • Readfds:被读监控的文件描述符集
  • Writefds:被写监控的文件描述符集
  • Exceptfds:被异常监控的文件描述符集
  • Timeout:定时器

系统提供了4个宏对描述符集进行操作:

#include <sys/select.h> 
void FD_SET(int fd, fd_set *fdset)
void FD_CLR(int fd, fd_set *fdset)
void FD_ZERO(fd_set *fdset)
void FD_ISSET(int fd, fd_set *fdset)

FD_SET将文件描述符fd添加到文件描述符集fdset中;
FD_CLR从文件描述符集fdset中清除文件描述符fd;
FD_ZERO清空文件描述符集fdset;
在调用select后使用FD_ISSET来检测文件描述符集fdset中的文件fd发生了变化。

实例:

FD_ZERO(&fds); //清空集合
sock1 = socket(……);
sock2 = socket(……);
bind(sock1,…);
bind(sock2,…);
listen(sock1,…);
listen(sock1,…);
FD_SET(sock1,&fds); //设置描述符
FD_SET(sock2,&fds); //设置描述符 
maxfdp=(sock1>sock2?sock1:sock2) + 1;
switch(select(maxfdp,&fds,NULL,NULL,&timeout))
	case -1: exit(-1);break; //select错误,退出程序
	case 0:break;
	default:
		if(FD_ISSET(sock1,&fds)) //测试sock1是否可读	
		accpet(sock1,…)
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐