文章目录
01 网络概述
1.1 网络通信概述
1.2 tcp-ip协议
1.3 端口
- 交换机可以将连接的电脑组成局域网
- 端口区分进程的通道
- 一台电脑上PID肯定不同,但是多台电脑PID可能相同,无法区分.另外比较困难知道对方的PID值
知名端口
0-1023端口,比如HTTP服务是80端口,FTP服务是21
netstat -an
查看端口状态
动态端口
动态端口范围在1024-65535之间,动态分配是指当一个系统进程或者应用程序进程需要通信时,它向主机申请一个端口,主机从可用端口号中分配一个可供它使用,当这个进程结束的时候,同时也释放了所占用的ip号
- 一台拥有ip地址的主机可以提供许多服务,比如http/ftp等服务,主机通过ip地址+端口号区分不同的服务
- 端口并不是一一对应的,比如你的电脑作为客户机访问一台www服务器,www服务器使用80端口和你的电脑通信,但你的电脑则可能使用3457端口
1.4 IP
- 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
- 127.0.0.1可以代表本地IP地址
- 255.255.255用于回路测试
1.5 子网掩码
1.6 socket简介
socket.socket(AddressFamily, Type)
socket是不同主机之间通信的一种方式
创建socket
- TCP-socket
# TCP慢,但是稳定
import socket
s = socket.socket(socket.AF_INET, socker.SOCK_STREAM)
print("Socket Created")
- UDP-socket
# 速度快,但不稳定
import socket
s = socket.socket(socket.AF_INET, socker.SOCK_DGRAM)
1.7 udp介绍
1.8 udp网络程序-发送数据
创建一个udp客户端流程很简单,具体步骤如下:
- 创建客户端套接字
- 发送/接受数据
- 关闭套接字
from socket import *
# 1. 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 2. 准备接受方的地址
sendAddr = ('192.168.0.103', 8081)
# 3. 从键盘上获取数据
sendData = input("请输入要发送的数据").encode("utf-8")
# 4. 发送数据到指定的电脑上
udpSocket.sendto(sendData, sendAddr)
# 5. 关闭套接字
udpSocket.close()
1.9 udp网络程序-接受数据
from socket import *
# 1. 创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 2. 准备接受方的地址
sendAddr = ('192.168.0.103', 8081)
# 3. 从键盘上获取数据
sendData = input("请输入要发送的数据").encode("utf-8")
# 4. 发送数据到指定的电脑上
udpSocket.sendto(sendData, sendAddr)
"""
如果没有发送过信息,则要指定默认端口,否则程序无法知道发送给目标主机的哪个端口
"""
# 5. 等待接受对方发送的数据
recvData = udpSocket.recvfrom(1024) # 1024表示本次接受的最大字节数
"""
接受的内容:
(内容, ('ip', 端口))
"""
print(recvData)
udpSocket.close()
说明
- 每次重新运行,端口号都不一样,这个数字标志这个网络程序所用端口号,如果没有设置,那么系统将随机分配
- 如果其他网络程序想要向此发送数据,向这个端口发送即可
1.10 udp绑定信息
1. 绑定信息
- 为了不与其他的网络程序占用同一端口号,在编程中udp的端口号一般不绑定
- 如果是一个服务器端的程序,那么是需要绑定的,也就是端口绑定
2. 绑定示例
from socket import *
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 1.绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
bindAddr = ('', 7788) # ip地址和端口号,ip地址一般不填写,表示本机的任意一个ip
udpSocket.bind(bindAddr)
# 2.等待接受对方发送的数据
recvData = udpSocket.recvfrom(1024) # 1024表示本次接受的最大字节数
print(recvData)
# 关闭socket
udpSocket.close()
- 一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程
1.11 udp网络通信过程
1.12 echo服务器
from socket import *
# 1. 创建Socket
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 2. 绑定本地信息
bindAddr = ('', 7788)
udpSocket.bind(bindAddr)
num = 0
while num < 50:
# 3. 等待接受对方发送的数据
recvData = udpSocket.recvfrom(1024) # 1024表示本次接受的最大字节数
# 4. 将接受到的数据再发送给对方
udpSocket.sendto(recvData[0], recvData[1])
# 5. 统计信息
print("将接到的第%d个数据返回给对方,内容为%s" % (num, recvData[0]))
num += 1
udpSocket.close()
1.13 udp应用: 聊天室
from socket import *
from time import ctime
# 1. 创建Socket
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 2. 绑定本地信息
bindAddr = ('', 7788)
udpSocket.bind(bindAddr)
num = 0
while num < 50:
# 3. 等待接受对方发送的数据
recvdata = udpSocket.recvfrom(1024) # 1024表示本次接受的最大字节数
print("[时间:%s],[ip地址%s],[端口号:%s],[聊天内容:%s]" % (ctime(), recvdata[1][0],recvdata[1][1], recvdata[0]))
udpSocket.close()
1.14 udp总结
- upd是TCP/IP协议族中的一种协议,能够完成不同机器进程之间的数据通信
- udp服务器、客户端
- udp的服务器和客户端的区分:往往是通过
请求服务
和提供服务
来进行区分的 - 请求服务的一方称为
客户端
- 提供服务的一方称为
服务器
- udp的服务器和客户端的区分:往往是通过
- udp绑定问题
- 一般情况下,服务器端需要绑定端口,目的是为了让其他客户端能够正确发送到此程序
- 客户端,一般不需要绑定,而是让操作系统随机分配;这样就不会因为需要绑定的端口被占用而导致程序无法运行的情况
1.15 综合作业-模拟QQ
- 使用多线程完成一个
全双工
的QQ聊天程序
from threading import Thread
from socket import *
udpSocket = None
port = 0
ipaddr = ''
# 1. 发送数据
def send():
while True:
sendInfo = input("<<")
udpSocket.sendto(sendInfo.encode('gb2312'), (ipaddr, port)) # 发送信息
# 2. 接受数据
def rece():
while True:
recvInfo = udpSocket.recvfrom(1024) # 接受信息
print(">>%s:%s" % (str(recvInfo[1]), recvInfo[0]))
def main():
global udpSocket
global port
global ipaddr
ipaddr = input("对方的ip")
port = int(input("对方的端口"))
# 绑定ip和端口
udpSocket = socket(AF_INET, SOCK_DGRAM)
udpSocket.bind(("", 4567)) # 接受元祖作为输入参数
# 开启多线程
Thread1 = Thread(target=send)
Thread2 = Thread(target=rece)
Thread1.start()
Thread2.start()
Thread1.join()
Thread2.join()
if __name__ == '__main__':
main()