首页 > 其他分享 >socket UDP

socket UDP

时间:2023-05-22 11:01:13浏览次数:32  
标签:UDP addr server 接字 data socket


UDP 套接字

概述

在使用 TCP 编程和使用 UDP 编程之间存在一些本质差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议不同于 TCP 提供的面向连接的可靠字节流。从资源的角度来看,相对来说UDP套接字开销较小,因为不需要维持网络连接,而且因为无需花费时间来连接,所以UDP套接字的速度也较快。

因为UDP提供的是不可靠服务,所以数据可能会丢失。如果数据对于我们来说非常重要,就需要小心编写UDP客户程序,以检查错误并在必要时重传。实际上,UDP套接字在局域网中是非常可靠的。

socket UDP_服务器


图:UDP 客户 / 服务器程序使用的套接字函数

上图展示了客户与服务器使用UDP套接字进行通信的过程。在UDP套接字程序中,客户不需要与服务器建立连接,而只管直接使用sendto函数给服务器发送数据报。同样的,服务器不需要接受来自客户的连接,而只管调用recvfrom函数,等待来自某个客户的数据到达。

套接字成为了应用程序进行通信的一种抽象机制。每一个进程都有一个或者多个套接字。当生成一个套接字的时候,就会为它分配一个端口号。我们是在C/S架构上应用UDP套接字编程。那么,服务器总是在等待客户端的请求。客户端在请求的时候,它会告知目的地址(服务器的IP地址和目的进程的端口号)。

创建套接字

可以使用系统调用socket来创建一个套接字并返回该套接字的文件描述符。

from socket import *    # 包含socket库

s = socket(AF_INET,SOCK_DGRAM)

创建的套接字是一条通信线路的一个端点。

family

family参数指定哪种协议族,常见的协议族包括 AF_UNIX 和 AF_INET。AF_UNIX 用于通过文件系统实现的本地套接字,AF_INET 用于网络套接字。

type

type参数指定这个套接字的通信类型,取值包括 SOCK_STREAM 和 SOCK_DGRAM。
SOCK_STREAM 即流套接字,基于 TCP,提供可靠,有序的服务。
SOCK_DGRAM 即数据报套接字,基于 UDP,提供不可靠,无序的服务。

protocol

protocol允许为套接字指定一种协议。对于 AF_UNIX 和 AF_INET,我们使用默认值即可。

以下代码创建一个 UDP socket,family使用 AF_INET,type 使用 SOCK_DGRAM,protocol 协议使用默认的 0 值。

命名套接字

要想让创建的套接字可以被其他进程使用,那必须给该套接字命名。对套接字命名的意思是指将该套接字关联一个IP地址和端口号,可以使用系统调用bind来实现。

server_port = 8000      # 服务器端口

# 创建套接字,设置Ipv4地址以及指定UDP连接

server_socket = socket(AF_INET,SOCK_DGRAM)

# 绑定IP地址和端口号。监听该端口

server_socket.bind(('',server_port))

bind系统调用把参数address中的地址分配给与文件描述符socket关联的套接字。

对于客户套接字,我们一般不需要指定套接字的端口号,而对于服务器套接字,我们需要指定套接字的端口号以便让客户正确向服务器发送数据。如果不需要指定端口号,可以将server_port的值赋为0。

如果我们没特别为套接字绑定IP地址,可以让操作系统选择一个,即address使用地址0.0.0.0,使用INADDR_ANY来表示这个地址常量。

下面是服务器代码:

# python3 实现循环无连接服务器

from socket import *    # 包含socket库

server_port = 8000      # 服务器端口

 

# 创建套接字,设置Ipv4地址以及指定UDP连接

server_socket = socket(AF_INET,SOCK_DGRAM)

# 绑定IP地址和端口号。监听该端口

server_socket.bind(('',server_port))

while True:

print("receive data:")

# 从客户端发来的包中获取数据存放在data中,将源地址放在client_address中。

# 设置缓存大小为4096。完成这些功能需要使用函数recvfrom.

    data,client_address = server_socket.recvfrom(4096)

print(data.decode())    # 打印客户端的数据

    server_socket.sendto(b"success!",client_address)

server_socket.close()

客户端代码:

# python3实现的客户端代码

from socket import * # 包含网络模块

#服务器地址以及端口号

#127.0.0.1是本地回环地址,经常用来进行测试,也可以使用域名localhost来代替该ip地址

server_ip = '127.0.0.1'

server_port = 8000

server_address = (server_ip, server_port)

#创建套接字    ipv4地址以及UDP协议

client_socket = socket(AF_INET,SOCK_DGRAM)

 

while True:

    data = input("please input:")

    client_socket.sendto(data.encode(),server_address)

    recv,server_addr = client_socket.recvfrom(4096)

print(recv.decode())

 

client_socket.close()

 

总的来说,在使用UDP作为传输层协议的时候,客户端需要知道服务器的IP地址和目的端口号。由于UDP是面向无连接的协议,因此,客户端使用sendto函数来发送。创建套接字的时候注意UDP是SOCK_DGRAM。服务器也使用sendto函数来发送响应给客户端。recvfrom函数能够接受包,并知晓客户端的地址。

使用Python socket编程实现简单的聊天室功能

服务器和客户端使用UDP编程,客户端两个线程一个负责接收,一个负责发送。

服务器:接收消息并保存地址,如果触发‘EXIT’关键字则从地址表中移除该地址

 

def main():

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 

    addr = ('127.0.0.1', 9999)

    s.bind(addr)

 

    logging.info('UDP Server on %s:%s...', addr[0], addr[1])

 

    user = {}  # {addr:name}

    while True:

        try:

            data, addr = s.recvfrom(1024)

            if not addr in user:

                for address in user:

                    s.sendto(data + ' 进入聊天室...'.encode(), address)

                user[addr] = data.decode()

                continue

 

            if 'EXIT' in data.decode('utf-8'):

                name = user[addr]

                user.pop(addr)

                for address in user:

                    s.sendto((name + ' 离开了聊天室...').encode(), address)

            else:

                print('"%s" from %s:%s' %

                      (data.decode('utf-8'), addr[0], addr[1]))

                for address in user:

                    if address != addr:

                        s.sendto(data, address)

 

        except ConnectionResetError:

            logging.warning('Someone left unexcept.')

客户端:两个线程,并设置接收线程为守护线程

 

def recv(sock, addr):

    '''

    一个UDP连接在接收消息前必须要让系统知道所占端口

    也就是需要send一次,否则win下会报错

    “   data=sock.recv(1024)

        OSError: [WinError 10022] 提供了一个无效的参数。   ”

    '''

    sock.sendto(name.encode('utf-8'), addr)

    while True:

        data = sock.recv(1024)

        print(data.decode('utf-8'))

 

 

def send(sock, addr):

    while True:

        string = input()

        message = name + ' : ' + string

        data = message.encode('utf-8')

        sock.sendto(data, addr)

        if string == 'EXIT':

            break

 

def main():

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    server = ('127.0.0.1', 9999)

 

    tr = threading.Thread(target=recv, args=(s, server), daemon=True)

    ts = threading.Thread(target=send, args=(s, server))

    tr.start()

    ts.start()

    ts.join()

    s.close()

 

if __name__ == '__main__':

    print("-----欢迎来到聊天室,退出聊天室请输入'EXIT'-----")

    name = input('请输入你的名称:')

    print('-----------------%s------------------' % name)

    main()

 

可以通过继承socket.socket类来重构,那样子显得跟规范一些

 

标签:UDP,addr,server,接字,data,socket
From: https://blog.51cto.com/u_1439909/6321651

相关文章

  • 基于 Socket 接口实现自定义协议通信
    访问【WRITE-BUG数字空间】_[内附完整源码和文档]根据自定义的协议规范,使用Socket编程接口编写基本的网络应用软件。掌握C语言形式的Socket编程接口用法,能够正确发送和接收网络数据包开发一个客户端,实现人机交互界面和与服务器的通信开发一个服务端,实现并发处理多个客户端......
  • C# socket的基本理解
    博客园中看到的比较准确的socket理解个人学习用途博客部分内容摘抄自网络......
  • AS3 Socket 通信基础(一)
    我们先来搞清几个概念,这有助于我们更加了解网络通信!  1、网络中进程之间如何通信?  首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可......
  • springboot集成websocket
    导入依赖1<dependency>2<groupId>org.springframework.boot</groupId>3<artifactId>spring-boot-starter-websocket</artifactId>4</dependency>编写配置类@ConfigurationpublicclassWebSocketConfig{@Beanpub......
  • 13-1 udp和internet层协议 13-2IP地址组成和分类13-4 网卡配置文件和命令 13-5 网络理
    一、查看当前机器广播的地址和mac[root@centos8~]#arp-n查看当前机器的广播地址[root@centos8~]#tcpdump-ieth0arp-nn抓包[root@centos8~]#ipaa10.0.0.100/24deveth0添加多网卡命令[root@centos8~]#arping10.0.0.100查看IP有没有被占用二、查看相关包有......
  • permission denied while trying to connect to the Docker daemon socket at unix://
     001、普通用户操作docker遇到如下问题permissiondeniedwhiletryingtoconnecttotheDockerdaemonsocketatunix:///var/run/docker.sock:Get"http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/json":dialunix/var/run/docker.sock:connect:permissiondenied......
  • c++ socket API使用流程(转)
    原文:https://blog.csdn.net/weixin_43687811/article/details/122657720?spm=1001.2101.3001.6650.16&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-16-122657720-blog-121686590.pc_relevant_multi_platform_featuressor......
  • SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息
    SpringBoot实现WebSocket发送接收消息+Vue实现SocketJs接收发送消息参考:1、https://www.mchweb.net/index.php/dev/887.html2、https://itonline.blog.csdn.net/article/details/81221103?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2......
  • WebSocket 服务端-SupperWebSocket
    通过对FlectWebsocket和SupperWebSocket的比较,初步总结出WebSocket服务端的实现步骤:建立WebSocket服务,并注册事件(OpendOnMessageReceivedClosed)配置监听地址Fleck的WebSocketServer(url)url="ws://0.0.0.0:10020"而SupperWebSocket.Setup(ip,port)启动监听S......
  • 天翼云CDN全站加速产品对websocket协议的支持
    本文分享自天翼云开发者社区《天翼云CDN全站加速产品对websocket协议的支持》,作者:郭****迎1、背景介绍HTTP协议有一个缺陷:通信只能由客户端发起。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就只能使用轮询的方案。轮询是在特定的时间间隔(如每1秒),由浏览......