- 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kun1280437633/article/details/80316396
1. 不同电脑上的进程之间如何通信
首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!
在1台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这是行不通的。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用进程(进程)。
这样利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
注意:
- 所谓
进程
指的是:运行的程序以及运行时用到的资源这个整体称之为进程(在讲解多任务编程时进行详细讲解)- 所谓
进程间通信
指的是:运行的程序之间的数据共享- 后面课程中会详细说到,像网络层等知识,不要着急
2. 什么是socket
socket(简称 套接字
) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的
例如我们每天浏览网页、QQ 聊天、收发 email 等等
3. 创建socket
在 Python 中 使用socket 模块的函数 socket 就可以完成:
import socket
socket.socket(AddressFamily, Type)
说明:
函数 socket.socket 创建一个 socket,该函数带有两个参数:
- Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
- Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
说明
-
套接字使用流程 与 文件的使用流程很类似
- 创建套接字
- 使用套接字收/发数据
- 关闭套接字
- 如果需要做成一个服务器端的程序的话,是需要绑定端口的
str->bytes:encode编码
bytes->str:decode解码
4. 什么是端口号
端口号是唯一标识运行网络进程的数字
(1)端口号的作用就是区分同一台电脑上不同的进程
(2)端口号在通过一台电脑上不能有重复使用
(3)端口号在不同电脑上可以重复
(4)端口有两种分配方式:固定端口(绑定),随机端口(系统分配)
(5)端口号有:知名端口(0-1023)、动态端口(1024-65535)
4. UDP和TCP区别
代码:
UDP聊天器
import socket
def send_msg(udp_socket):
"""发送消息"""
send_msg = input('请输入要发送的数据:')
send_ip = input('请输入接收消息的IP地址:')
send_port = int(input('请输入要接收消息的端口号:'))
send_addr = (send_ip, send_port)
udp_socket.sendto(send_msg.encode('utf-8'), send_addr)
def recv_msg(udp_socket):
"""接收消息"""
print('准备接收数据:')
recv_data, recv_addr = udp_socket.recvfrom(1024)
print('%s 发来消息: %s' % (recv_addr, recv_data.decode('utf-8'))) # Ubuntu 网络调试助手发来的消息使用 UTF-8解码
def main():
"""使用一个socket实现收和发的功能"""
# 创建UDP套接字--怎么在代码提示的时候不需要区分大小写?
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
local_addr = ("", 1314) #下标0是本机IP地址,下表1是使用的端口号
udp_socket.bind(local_addr)
while True:
# 打印提示信息
print('==============================')
print('1:发送消息')
print('2:接收消息')
print('==============================')
# 获取用户选择的操作
command = input('请输入要操作的功能序号:')
# 判断用户的操作类型
if command == '1':
# 发送数据
send_msg(udp_socket)
elif command == '2':
# 接收数据
recv_msg(udp_socket)
else:
# 无法处理的指令,退出循环
break
# 关闭套接字
udp_socket.close()
if __name__ == '__main__':
main()
import socket
import threading
UDP聊天器多任务版
def send_msg(udp_socket):
"""发送消息"""
while True:
send_msg = input('请输入要发送的数据:')
send_ip = input('请输入接收消息的IP地址:')
send_port = int(input('请输入要接收消息的端口号:'))
send_addr = (send_ip, send_port)
udp_socket.sendto(send_msg.encode('utf-8'), send_addr)
def recv_msg(udp_socket):
"""接收消息"""
while True:
print('准备接收数据:')
recv_data, recv_addr = udp_socket.recvfrom(1024)
print('%s 发来消息: %s' % (recv_addr, recv_data.decode('utf-8'))) # Ubuntu 网络调试助手发来的消息使用 UTF-8解码
def main():
"""使用一个socket实现收和发的功能"""
# 创建UDP套接字--怎么在代码提示的时候不需要区分大小写?
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
local_addr = ("", 1314)
udp_socket.bind(local_addr)
# 开启发送线程
# send_msg(udp_socket)
t1 = threading.Thread(target=send_msg, args=(udp_socket,))
t1.start()
# 开启接收线程
# recv_msg(udp_socket)
t2 = threading.Thread(target=recv_msg, args=(udp_socket,))
t2.start()
# 关闭套接字
# udp_socket.close()
if __name__ == '__main__':
main()
TCP客户端的收发数据
import socket
def main():
"""使用TCP协议发送和接收数据"""
# 创建TCP套接字, 参数二是 SOCK_STREAM
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# TCP客户端使用时必须先连接到服务器
server_addr = ('127.0.0.1', 8080)
tcp_client.connect(server_addr) # connect 接收一个元组
# 发送数据
tcp_client.send(b'hahaha') # 只要发送数据,不需要接收者的地址
# 接收数据
print('准备接收数据:')
recv_data = tcp_client.recv(1024) # 接收到的只有数据,没有发送者的地址
print(recv_data.decode('utf-8'))
# 关闭套接字
tcp_client.close()
if __name__ == '__main__':
main()
TCP服务器的收发数据
import socket
def main():
"""使用TCP服务器完成一个客户端的数据收发"""
# 创建TCP套接字
tcp_sever = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址信息
local_addr = ("", 1315)
tcp_sever.bind(local_addr)
# 设置为被动模式--128是最大可以同时连接的客户端数量
tcp_sever.listen(128)
while True:
# 获取客户端连接,得到一个元组,0号下标是和客户端连接的套接字,1号下标是客户端地址
print('等待客户端连接----')
client_soc, client_addr = tcp_sever.accept()
while True:
# 向客户端发送数据
print('发送数据~~')
client_soc.send(b'hahaha')
# 接收客户端数据
print('准备接收数据!')
recv_msg = client_soc.recv(1024)
# 判断是否要断开客户端链接
if recv_msg:
# 有数据
print("接收到数据:",recv_msg)
else:
# 没有收到数据
print('客户端已经断开链接')
break
# 关闭客户端套接字
client_soc.close()
# 关闭服务器套接字
tcp_sever.close()
if __name__ == '__main__':
main()