发布时间:2018-05-04 19:44:24编辑:Run阅读(5156)
基于UDP协议的socket
udp是无连接的,启动服务之后可以直接接受消息,不需要提前建立连接,UDP必须是server端先接受消息
简单版
server端代码
import socket # 创建一个服务器的套接字基于udp,type=socket.SOCK_DGRAM表示使用udp协议 udp_sk = socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind(('127.0.0.1', 9555)) # 绑定服务器的ip和端口的套接字 # udp协议不用建立连接 msg, addr = udp_sk.recvfrom(1024) # 接收1024字节的消息 msg表示内容,addr表示ip和端口 print(msg.decode('utf-8')) udp_sk.sendto('hello'.encode('utf-8'), addr) #发送消息,需写入对方的ip和端口 udp_sk.close()
client端代码
import socket ip_port = ('127.0.0.1', 9555) # 服务器的ip与端口 # 创建一个服务器的套接字,基于udp协议 type=socket.SOCK_DGRAM udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 发送消息并编码成utf-8,需要传ip和端口 udp_sk.sendto('你好吗'.encode('utf-8'), ip_port) # 接收1024字节的消息 加 ip+端口 back_msg, addr = udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'), addr) udp_sk.close()
先运行server,再运行client
server执行结果
你好吗
client执行结果
hello ('127.0.0.1', 9555)
怎么改成手动输入,多人聊天?
server端代码
import socket # 创建一个服务器的套接字基于udp,type=socket.SOCK_DGRAM表示使用udp协议 udp_sk = socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind(('127.0.0.1', 9555)) # 绑定服务器的ip和端口的套接字 while True: # udp协议不用建立连接 msg, addr = udp_sk.recvfrom(1024) # 接收1024字节的消息 msg表示内容,addr表示ip和端口 print(msg.decode('utf-8')) inp = input('>>>').strip().encode('utf-8') udp_sk.sendto(inp, addr) # 发送消息,需写入对方的ip和端口 udp_sk.close()
client端代码
import socket ip_port = ('127.0.0.1', 9555) # 服务器的ip与端口 # 创建一个服务器的套接字,基于udp协议 type=socket.SOCK_DGRAM udp_sk = socket.socket(type=socket.SOCK_DGRAM) while True: # 发送消息,需要传ip和端口 inp = input('>>>').strip() if inp == 'q': # 判断当内容为q的时候,跳出循环,退出程序 break udp_sk.sendto(inp.encode('utf-8'), ip_port) # 接收1024字节的消息 加 ip+端口 back_msg, addr = udp_sk.recvfrom(1024) print(back_msg.decode('utf-8')) udp_sk.close()
先运行server,再运行client两次(模拟多人),运行结果
socket基于UDP协议,如果是2个客户端,都向server发送消息,那么server对于client,还是有优先顺序的(谁发送的数据,被server接受到,那么就先回复谁(网络延迟,带宽...的影响,并不是先发送就先收到))
socket(基于UDP协议)进阶聊天版--加上和不同人名通信(不同颜色)
选运行server,在运行client两次(模拟多个用户)
server端代码
import socket # 创建一个服务器的套接字基于udp,type=socket.SOCK_DGRAM表示使用udp协议 udp_sk = socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind(('127.0.0.1', 9555)) # 绑定服务器的ip和端口的套接字 lst = {'sam': '\033[1;31m', 'tom': '\033[1;34m'} # 对不同人设置不同颜色 while True: # udp协议不用建立连接 msg, addr = udp_sk.recvfrom(1024) # 接收1024字节的消息 msg表示内容,addr表示ip和端口 name, mesg = msg.decode('utf-8').split(':') color = lst.get(name.strip(), '') print('{}{}\033[0m'.format(color, msg.decode('utf-8'))) inp = input('>>>').strip().encode('utf-8') udp_sk.sendto(inp, addr) # 发送消息,需写入对方的ip和端口 udp_sk.close()
client端代码
import socket ip_port = ('127.0.0.1', 9555) # 服务器的ip与端口 # 创建一个服务器的套接字,基于udp协议 type=socket.SOCK_DGRAM udp_sk = socket.socket(type=socket.SOCK_DGRAM) name = input('>>>').strip() while True: # 发送消息,需要传ip和端口 inp = input('>>>').strip() if inp == 'q': # 判断当内容为q的时候,跳出循环,退出程序 break udp_sk.sendto('{} : {}'.format(name, inp).encode('utf-8'), ip_port) # 接收1024字节的消息 加 ip+端口 back_msg, addr = udp_sk.recvfrom(1024) print(back_msg.decode('utf-8')) udp_sk.close()
运行结果
每次发消息需要encode,接收消息需要decode,这样很麻烦?怎么做可以省去这些步骤?,这个时候可以自定义一个类,继承了socket类,能够实现高可用,定制需求
创建一个mysocket.py文件,内容如下
from socket import * #从socket模块中导入所有方法 class Mysocket(socket): # 继承socket类 def __init__(self, coding='utf-8'): self.coding = coding # 使用默认参数,设置字符编码 utf-8 super().__init__(type=SOCK_DGRAM) # 执行父类的__init__方法 def my_recv(self, num): msg, addr = self.recvfrom(num) return msg.decode(self.coding), addr # 接收消息这里解码 def my_send(self, msg, addr): return self.sendto(msg.encode(self.coding), addr) # 发送消息这么编码
server端代码
from mysocket import Mysocket sk = Mysocket() sk.bind(('127.0.0.1', 9090)) while True: msg, client_addr = sk.my_recv(1024) # udp协议不用建立连接 print(msg) inp = input('>>>').strip() sk.my_send(inp, client_addr) sk.close()
client端代码
from mysocket import Mysocket sk = Mysocket() while True: inp = input('>>>').strip() if inp == 'q':break sk.my_send(inp, ('127.0.0.1', 9090)) msg, addr = sk.my_recv(1024) if msg == 'q':break print(msg) sk.close()
先运行server,在运行client,执行结果为
时间同步服务,基于udp协议完成的
假如有一个标准时间的server服务端,client可以从server获取标准时间。
server端代码
import socket import time sk = socket.socket(type=socket.SOCK_DGRAM) sk.bind(('127.0.0.1', 9090)) while True: msg, addr = sk.recvfrom(1024) sk.sendto(time.strftime('%Y-%m-%d %H:%M:%S').encode('utf-8'), addr) # 发送一个格式化时间给client sk.close()
client端代码
import time sk = socket.socket(type=socket.SOCK_DGRAM) while True: sk.sendto('time'.encode('utf-8'),('127.0.0.1', 9090)) ret,addr = sk.recvfrom(1024) print(ret.decode('utf-8')) time.sleep(2) sk.close()
先运行server在运行client,效果为
查看TCP和UDP的套接字
socket参数的详解
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
创建socket对象的参数说明:
family | 地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 (AF_UNIX 域实际上是使用本地 socket 文件来通信) |
type | 套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。 SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。 SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。 |
proto | 协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。 |
fileno | 如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。 与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。 这可能有助于使用socket.close()关闭一个独立的插座。 |
下一篇: python3-socket黏包现象
47604
45983
36909
34467
29079
25713
24565
19714
19245
17756
5564°
6155°
5690°
5737°
6703°
5482°
5484°
5988°
5965°
7295°