网络通信概述
用网络可以把多方连接在一起,然后可以进行数据传输
网络编程就是,让在不同的电脑上的软件能够进行数据传输,即进程之间的通信
TCP/IP协议
- 五层模型
互联网的核心是一系列协议,总称为”互联网协议”(Internet Protocol Suite)。它们对电脑如何连接和组网,做出了详尽的规定。理解了这些协议,就理解了互联网的原理。其中最重要的两个协议是TCP和IP 协议,所以,⼤家把互联⽹的协议简称TCP/IP协议。
互联网的实现,分成好几层。每一层都有自己的功能,如何分层有不同的模型。这里把互联网分成五层:最底下的一层叫做”实体层”(Physical Layer),最上面的一层叫做”应用层”(Application Layer),中间的三层(自下而上)分别是”链接层”(Link Layer)、”网络层”(Network Layer)和”传输层”(Transport Layer)。越下面的层,越靠近硬件;越上面的层,越靠近用户。
-
层与协议
每一层都是为了完成一种功能。为了实现这些功能,就需要大家都遵守共同的规则。大家都遵守的规则,就叫做”协议”(protocol)。 -
IP协议
⽹络IP中,国际规定有⼀部分IP地址是⽤于局域⽹使⽤,也 就是属于私⽹IP,不在公⽹中使⽤的,它们的范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
IP地址127.0.0.1 代表本机IP地址,等价于localhost, ⽤ http://127.0.0.1 就可以测试本机中配置的Web服务器。
socket编程
本地进程间通信:
- 队列
- 同步(互斥锁,条件变量等)
- 管道
socket(简称套接字) 是进程间通信的⼀种⽅式, 能实现不同主机间的进程间通信,我们⽹络上各种各样的服务⼤多都是基于 Socket 来完成通信的。
创建⼀个tcp socket(tcp套接字)
创建⼀个udp socket(udp套接字)
UDP ⽤户数据报协议,是⼀个⽆连接的简单的⾯向数据报的运输层协议,每个数据报都是一个独立的信息。UDP不提供可靠性,它只是把应⽤程序传给IP层的数据报发送出去,但是并不能保证它们能到达⽬的地,到达⽬的地的时间以及内容的正确性都是不能被保证的。由于UDP在传输数据报前不⽤在客户和服务器之间建⽴⼀个连接,且没有超时重发等机制,故⽽传输速度很快。
#server端:
import socket
#1 创建scoket对象(实例化)
#family:AF_INET(IPv4) AF_INET6(IPv4) ====网络曾协议
#type: #SOCK_STREAM(TCP) SOCK_DGRAM(UDP) =====传输层协议
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('qq用户server上线......')
print('等待客户端UDP的连接....')
#通过添加死循环使server和client不断传输信息
while True:
#3.接收客户端的连接(接收传输数据和地址)
recvdata, address = udpServer.recvfrom(1024)
print('接收到client的数据:>>', recvdata.decode('utf-8'))
if recvdata == b'quit':
print('聊天结束')
break
#4.给客户端回复消息
send_data=input('server:>>').encode('utf-8')
if not send_data:
continue
udpServer.sendto(send_data,address)
#5.关闭socket对象
udpServer.close()
#客户端:
import socket
udpClient=socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
print("qq用户client上线.....")
while True:
#给server发消息
message = input('给server发送的消息:').encode('utf-8')
if not message:
continue
udpClient.sendto(message, ('192.168.43.105', 9001))
if message == b'quit':
break
#接收server的消息
recvData, address = udpClient.recvfrom(1024)
print('接收server的数据:>>', recvData.decode('utf-8'))
udpClient.close()
TCP传输控制协议(英语:Transmission Control Protocol,缩写为TCP):是一种面向连接的、可靠的、基于字节流的传输层通信协议。
import socket
server=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
server.bind(('0.0.0.0',9001))
server.listen(5)
print('server start...')
clientSocketObj, clientAddress = server.accept()
while True:
recv_data=clientSocketObj.recv(1024)
print('接受到客户端发送的消息:',recv_data.decode('utf-8'))
if recv_data =='quit':
break
send_data= input('服务端发送的消息:').encode('utf-8')
if not send_data:
continue
clientSocketObj.send(send_data)
clientSocketObj.close()
server.close()
import socket
client=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
client.connect(('192.168.43.105',9001))
while True:
send_data=input('客户端发送消息:').encode('utf-8')
if not send_data:
continue
client.send(send_data)
recv_data=client.recv(1024).decode('utf-8')
print('接受到服务端发送的消息:',recv_data)
if recv_data == 'quit':
break
client.close()
TCP详解
TCP三次握手:
- 两个包:同步序列标号 SYN ; 确认包 ACK
- 四种状态:SYN_SENT, LISTEN, SYN_RECV, ESTABLISHED
在三次握手中,客户端和服务器端都发送两个包SYN和ACK,只不过服务器端的两个包是一次性发过来的,客户端的两个包是分两次发送的。
TCP四次分手:
当A端和B端要断开连接时:
- 两个包: FIN:Finish ; ACK:确认序号
并发服务器
并发服务器是socket应用编程中最常见的应用模型。根据连接方式分为长连接和短连接.
单进程服务器:同一时刻只能为一个客户进行服务,不能同时为多个客户服务。
多进程服务器:
优点: 通过为每个客户端创建⼀个进程的⽅式,能够同时为多个客户端进⾏服务。
缺点: 当客户端不是特别多的时候,这种⽅式还⾏,如果有⼏百上千个,就不可取了,因为每次创建进程等过程需要耗费较⼤的资源。
基于TCP多进程服务器:
#server端
def dealWithClient(clientSocketObj, clientAddress):
while True:
recv_data = clientSocketObj.recv(1024).decode('utf-8')
print(clientAddress[0] + str(clientAddress[1]) + ':>' + recv_data)
if recv_data == 'quit':
break
clientSocketObj.close()
import socket
from multiprocessing import Process
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',9001))
server.listen(5)
print('server start......')
while True:
clientSocketObj,clientAddress=server.accept()
p=Process(target=dealWithClient,args=(clientSocketObj,clientAddress))
p.start()
#client1:
import socket
client=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
client.connect(('172.25.254.43',9001))
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()
#client2:
import socket
client=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
client.connect(('172.25.254.43',9001))
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()