前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python3--socket编程(udp协议)

python3--socket编程(udp协议)

作者头像
py3study
发布2018-08-02 17:06:15
9801
发布2018-08-02 17:06:15
举报
文章被收录于专栏:python3python3

基于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两次(模拟多人),运行结果

download.gif
download.gif

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()

运行结果

download.gif
download.gif

每次发消息需要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,执行结果为

download.gif
download.gif

时间同步服务,基于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,效果为

download.gif
download.gif

查看TCP和UDP的套接字

blob.png
blob.png

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()关闭一个独立的插座。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-05-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档