一.TCP/IP协议
TCP/IP协议(传输控制协议/互联网协议)是一组特别的协议,包括:TCP,IP,UDP,ARP等,这些被称为子协议。在这些协议中,最重要、最著名的就是TCP和IP。因此,大部分网络管理员称整个协议族为“TCP/IP”。
二.TCP与UDP
1.UDP用户数据报协议
UDP ⽤户数据报协议,是⼀个⽆连接的简单的⾯向数据报的运输层协议。UDP不提供可靠性,它只是把应⽤程序传给IP层的数据报发送出去,但 是并不能保证它们能到达⽬的地。由于UDP在传输数据报前不⽤在客户和服 务器之间建⽴⼀个连接,且没有超时重发等机制,故⽽传输速度很快。
UDP是⼀种⾯向⽆连接的协议,每个数据报都是⼀个独⽴的信息,包括完整 的源地址或⽬的地址,它在⽹络上以任何可能的路径传往⽬的地,因此能否到达⽬的地,到达⽬的地的时间以及内容的正确性都是不能被保证的。
UDP⼀般⽤于多点通信和实时的数据业务,⽐如:语⾳⼴播 ,视频,QQ,TFTP(简单⽂件传送)。SNMP(简单⽹络管理协议) , DNS(域名解释)
2.TCP传输控制协议
TCP: 传输控制协议(英语:Transmission Control Protocol,缩写为TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP三次握手:
三次握手
TCP连接是通过三次握手来连接的。
第一次握手
当客户端向服务器发起连接请求时,客户端会发送同步序列标号SYN到服务器,在这里我们设SYN为x,等待服务器确认,这时客户端的状态为SYN_SENT。
第二次握手
当服务器收到客户端发送的SYN后,服务器要做的是确认客户端发送过来的SYN,在这里服务器发送确认包ACK,这里的ACK为x+1,意思是说“我收到了你发送的SYN了”,同时,服务器也会向客户端发送一个SYN包,这里我们设SYN为y。这时服务器的状态为SYN_RECV。
一句话,服务器端发送SYN和ACK两个包。
第三次握手
客户端收到服务器发送的SYN和ACK包后,需向服务器发送确认包ACK,“我也收到你发送的SYN了,我这就给你发个确认过去,然后我们即能合体了”,这里的ACK为y+1,发送完毕后,客户端和服务器的状态为ESTABLISH,即TCP连接成功。
在三次握手中,客户端和服务器端都发送两个包SYN和ACK,只不过服务器端的两个包是一次性发过来的,客户端的两个包是分两次发送的。
TCP四次分手:
四次挥手
当A端和B端要断开连接时,需要四次握手,这里称为四次挥手。
断开连接请求可以由客户端发出,也可以由服务器端发出,在这里我们称A端向B端请求断开连接。
第一次挥手
A端向B端请求断开连接时会向B端发送一个带有FIN标记的报文段,这里的FIN是Finish的意思。
第二次挥手
B端收到A发送的FIN后,B段现在可能现在还有数据没有传完,所以B端并不会马上向A端发送FIN,而是先发送一个确认序号ACK,意思是说“你发的断开连接请求我收到了,但是我现在还有数据没有发完,请稍等一下呗”。
第三次挥手
当B端的事情忙完了,那么此时B端就可以断开连接了,此时B端向A端发送FIN序号,意思是这次可以断开连接了。
第四次挥手
A端收到B端发送的FIN后,会向B端发送确认ACK,然后经过两个MSL时长后断开连接。
MSL是Maximum Segment Lifetime,最大报文段生存时间,2个MSL是报文段发送和接收的最长时间
三.socket编程
1.网络中如何标识一个进程?
⽹络层的“IP地址”可以唯⼀标识⽹络中的主机,⽽传输层的“协议+端⼝”可以唯⼀标识主机中的应⽤程序(进程)。因此利用IP地址,协议,端⼝就可以标识⽹络的进程。
2.什么是socket?
socket(简称套接字) 是进程间通信的⼀种⽅式, 能实现不同主机间的进程间通信,我们⽹络上各种各样的服务⼤多都是基于 Socket 来完成通信的。
3.如何创建socket?
在 Python 中 使⽤socket 模块的函数 socket 就可以完成: socket.socket(AddressFamily, Type)
1). Address Family:
AF_INET: IPV4⽤于 Internet 进程间通信
AF_INET6: IPV6⽤于 Internet 进程间通信
2). Type:套接字类型
SOCK_STREAM: 流式套接字,主要⽤于 TCP 协议
SOCK_DGRAM: 数据报套接字,主要⽤于 UDP 协 议
四.python实现UDP与TCP网络通信
1.UDP网络程序
UDP服务端
import socket
#1.实例化socket对象
udpserver = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
#2.绑定IP和端口
#0.0.0.0代表开放所有的IP地址
udpserver.bind(('0.0.0.0',9001))
print('等待客户端UDP连接')
i=0
#3.接受客户端的连接
while 1:
recvdata,address = udpserver.recvfrom(1024)
print('接受到客户端的数据:',recvdata.decode('utf-8'))
#4.给客户端回复消息
udpserver.sendto(b'hello client%d' %i, address)
i+=1
#5.关闭socket对象
udpserver.close()
UDP客户端
import socket
i=0
udpclient = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
while 1:
udpclient.sendto(b'hello server%d' %i,('172.25.254.23',9001))
recvdata,address = udpclient.recvfrom(1024)
i+=1
print('接受服务端的数据:', recvdata.decode('utf-8'))
if recvdata.decode('utf-8') == 'quit':
break
udpclient.close()
2.TCP网络程序
TCP服务端
import socket
server = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
server.bind(('0.0.0.0',9888))
#监听是否有客户端连接
server.listen(5)
print('开始连接....')
#接受客户端的连接
clienSocketObj,clientAddress = server.accept()
recv_data = clienSocketObj.recv(1024).decode('utf-8')
print('接受到客户端发送的消息:',recv_data)
#给客户端发送消息
send_data = b'hello client'
clienSocketObj.send(send_data)
clienSocketObj.close()
server.close()
TCP客户端
import socket
client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#连接服务段
client.connect(('172.25.254.66',9888))
client.send(b'hello server')
#接受服务端的消息
recv_data = client.recv(1024).decode('utf-8')
print('接受服务端发送的消息:',recv_data)
client.close()
五.并发服务器
1.什么是并发服务器?
并发服务器是socket应用编程中最常见的应用模型。根据连接方式分为长连接和短连接.
长连接:建立SOCKET连接后不管是否使用都保持连接
短连接:双方有数据交互时,建立TCP连接,数据发送完成后断开连接
并发服务器模型根据处理方式可分为同步方式和异步方式。
2.多进程服务器
优点: 通过为每个客户端创建⼀个进程的⽅式,能够同时为多个客户端进⾏服务
缺点: 当客户端不是特别多的时候,这种⽅式还⾏,如果有⼏百上千个,就不 可取了,因为每次创建进程等过程需要好较⼤的资源。
3.基于TCP多进程服务器程序实现
服务器
import socket
from multiprocessing import Process
#实现多进程的方式
# 实例化对象
# 继承子类 一定要确定多进程要处理的任务
#任务:处理客户端请求并为其服务
def echoClient(clientSocketObj,clientAddress):
while 1:
#接受客户端发送的消息
recv_data = clientSocketObj.recv(1024).decode('utf-8')
print(clientAddress[0] + str(clientAddress[1]) + ':> ' + recv_data)
if recv_data == 'quit':
break
clientSocketObj.close(0)
#创建服务端socket对象
server = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#绑定地址和端口
server.bind(('0.0.0.0',9999))
#监听是否有客户端连接
server.listen(5)
print('sever start/...')
while True:
#接受客户端的连接accept
clientSocketObj,clientAddress = server.accept()
p = Process(target=echoClient,args=(clientSocketObj,clientAddress))
p.start()
客户端
import socket
#创建客户端socket对象
client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#连接服务端
client.connect(('172.25.254.66',9999))
while True:
#给服务的发送消息
send_data = input('client:>>').encode('utf-8')
if not send_data:
continue
client.send(send_data)
if send_data=='quit':
break
client.close()
同样我们还可以创建一个客户端2,同时给服务端发送消息,程序运行结果如下:
服务端接受的消息:
客户端1发送的消息:
客户端2发送的消息:
六.常见网络编程面试题目
1.简述 OSI 七层协议。
OSI是一个开放性的通信系统互连参考模型,他是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 ;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端的数据流。
2. 简述 TCP/IP 四层协议。
链路层(数据链路层/网络接口层):包括操作系统中的设备驱动程序、计算机中对应的网络接口卡
网络层(互联网层):处理分组在网络中的活动,比如分组的选路。
运输层:主要为两台主机上的应用提供端到端的通信。
应用层:负责处理特定的应用程序细节。
3. TCP 和 UDP 的区别是什么?
4. TCP 连接建立的时候 3 次握手的具体过程,以及其中的每一步是为什么?
第一次握手
当客户端向服务器发起连接请求时,客户端会发送同步序列标号SYN到服务器,在这里我们设SYN为x,等待服务器确认,这时客户端的状态为SYN_SENT。
第二次握手
当服务器收到客户端发送的SYN后,服务器要做的是确认客户端发送过来的SYN,在这里服务器发送确认包ACK,这里的ACK为x+1,意思是说“我收到了你发送的SYN了”,同时,服务器也会向客户端发送一个SYN包,这里我们设SYN为y。这时服务器的状态为SYN_RECV。
一句话,服务器端发送SYN和ACK两个包。
第三次握手
客户端收到服务器发送的SYN和ACK包后,需向服务器发送确认包ACK,“我也收到你发送的SYN了,我这就给你发个确认过去,然后我们即能合体了”,这里的ACK为y+1,发送完毕后,客户端和服务器的状态为ESTABLISH,即TCP连接成功。
5. TCP 断开连接的具体过程,其中每一步是为什么那么做?
四次挥手
当A端和B端要断开连接时,需要四次握手,这里称为四次挥手。
断开连接请求可以由客户端发出,也可以由服务器端发出,在这里我们称A端向B端请求断开连接。
第一次挥手
A端向B端请求断开连接时会向B端发送一个带有FIN标记的报文段,这里的FIN是Finish的意思。
第二次挥手
B端收到A发送的FIN后,B段现在可能现在还有数据没有传完,所以B端并不会马上向A端发送FIN,而是先发送一个确认序号ACK,意思是说“你发的断开连接请求我收到了,但是我现在还有数据没有发完,请稍等一下呗”。
第三次挥手
当B端的事情忙完了,那么此时B端就可以断开连接了,此时B端向A端发送FIN序号,意思是这次可以断开连接了。
第四次挥手
A端收到B端发送的FIN后,会向B端发送确认ACK,然后经过两个MSL时长后断开连接。
6. TCP 的十一种状态?
客户端独有的:(1)SYN_SENT (2)FIN_WAIT1 (3)FIN_WAIT2 (4)CLOSING (5)TIME_WAIT 服务器独有的:(1)LISTEN (2)SYN_RCVD (3)CLOSE_WAIT (4)LAST_ACK
共有的:(1)CLOSED (2)ESTABLISHED
7. 什么是 socket?简述基于 tcp 协议的套接字通信流程。
socket(简称套接字) 是进程间通信的⼀种⽅式, 能实现不同主机间的进程间通信
1.面向连接的套接字Socket通信工作流程
1).服务器先用 socket 函数来建立一个套接字,用这个套接字完成通信的监听。
2).用 bind 函数来绑定一个端口号和 IP 地址。因为本地计算机可能有多个网址和 IP,每一个 IP 和端口有多个端口。需要指定一个 IP 和端口进行监听。
3).服务器调用 listen 函数,使服务器的这个端口和 IP 处于监听状态,等待客户机的连接。
4).客户机用 socket 函数建立一个套接字,设定远程 IP 和端口。
5).客户机调用 connect 函数连接远程计算机指定的端口。
6).服务器用 accept 函数来接受远程计算机的连接,建立起与客户机之间的通信。
7).建立连接以后,客户机用 write 函数向 socket 中写入数据。也可以用 read 函数读取服务器发送来的数据。
8).服务器用 read 函数读取客户机发送来的数据,也可以用 write 函数来发送数据。
9).完成通信以后,用 close 函数关闭 socket 连接。
8. 简述基于 udp 协议的套接字通信流程。
1、创建一个socket,用函数socket();
2、绑定IP地址、端口等信息到socket上,用函数bind();
3、设置对方的IP地址和端口等属性;
4、发送数据,用函数sendto();
5、关闭网络连接;
9. TCP 为什么不是两次连接?而是三次握手?
为了实现可靠传输,通信双方需要判断自己已经发送的数据包是否都被接收方收到, 如果没收到, 就需要重发。
10. 为何基于 tcp 协议的通信比基于 udp 协议的通信更可靠?
TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。不过UDP的速度是TCP比不了的,而且UDP的反应速度更快。
11. 网络编程中设计并发服务器,使用多进程与多线程,请问有什么区别?
1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。两者都可以提高程序的并发度,提高程序运行效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
12. 大规模连接上来,并发模型怎么设计?
并发服务器是socket应用编程中最常见的应用模型。根据连接方式分为长连接和短连接.
长连接:建立SOCKET连接后不管是否使用都保持连接
短连接:双方有数据交互时,建立TCP连接,数据发送完成后断开连接