Top

第五章 网络和并发编程

1、python的底层网络交互模块有哪些

  socket,socketserver

2、简述OSI七层协议

  为了实现计算机系统的互连,OSI参考模型把整个网络的通信功能划分为7个层次,同时也定义了层次之间的相互关系以及各层所包括的服务及每层的功能。OSI的七层由低到高依次为:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,下三层(物理层、数据链路层、网络层)面向数据通信,而上三层(会话层、表示层、应用层)则面向资源子网,而传输层则是七层中最为重要的一层。它位于上层和下层中间,起承上启下的作用。

3、什么是C/S和B/S架构

  C/S 架构是一种典型的两层架构,其全称是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信。

  B/S架构的全称为Browser/Server,即浏览器/服务器结构。Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现,Browser客户端,WebApp服务器端和DB端构成所谓的三层架构。B/S架构的系统无须特别安装,只有Web浏览器即可。

4、简述TCP三次握手,四次挥手的流程。

  三次握手:

    第一次握手:客户端的应用进程主动打开,并向客户端发出请求报文段。其首部中:SYN=1,seq=x。

    第二次握手:服务器应用进程被动打开。若同意客户端的请求,则发回确认报文,其首部中:SYN=1,ACK=1,ack=x+1,seq=y。

    第三次握手:客户端收到确认报文之后,通知上层应用进程连接已建立,并向服务器发出确认报文,其首部:ACK=1,ack=y+1。当服务器收到客户端的确认报文之后,也通知其上层应用进程连接已建立。

  四次挥手:

    第一次挥手:数据传输结束以后,客户端的应用进程发出连接释放报文段,并停止发送数据,其首部:FIN=1,seq=u。

    第二次挥手:服务器端收到连接释放报文段之后,发出确认报文,其首部:ack=u+1,seq=v。此时本次连接就进入了半关闭状态,客户端不再向服务器发送数据。而服务器端仍会继续发送。

    第三次挥手:若服务器已经没有要向客户端发送的数据,其应用进程就通知服务器释放TCP连接。这个阶段服务器所发出的最后一个报文的首部应为:FIN=1,ACK=1,seq=w,ack=u+1。

    第四次挥手:客户端收到连接释放报文段之后,必须发出确认:ACK=1,seq=u+1,ack=w+1。 再经过2MSL(最长报文端寿命)后,本次TCP连接真正结束,通信双方完成了他们的告别。

  如果已经建立了TCP连接,但是客户端突然出现故障了怎么办?

    TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

5、什么是arp协议?

  ARP全称“Address Resolution Protocol”,地址解析协议。

  实现局域网内通过IP地址获取主机的MAC地址。

  MAC地址48位主机的物理地址,局域网内唯一。

  ARP协议类似DNS服务,但不需要配置服务。

  ARP协议是三层协议。

6、TCP和UDP的区别

  1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  3. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
  4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  5. TCP对系统资源要求较多,UDP对系统资源要求较少。

  为什么基于tcp协议的通信比基于udp协议的通信更可靠?

  TCP是面向连接的传输协议,每次都需要建立一个可以相互信任的连接,中间有个三次握手过程。而UDP是面向无连接的传输协议,不需要建立安全的连接

  UDP:效率高、不可靠、无连接、基于数据包的传输,能够传输的数据的长度有限。即时聊天工具用的是UDP。

7、什么是局域网和广域网?

  局域网和广域网是相对的概念。

  局域网(Local Area Network),简称LAN,是指在某一区域内由多台计算机互联成的计算机组。“某一区域”指的是同一办公室、同一建筑物、同一公司和同一学校等,一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打印机共享、扫描仪共享、工作组内的日程安排、电子邮件和传真通信服务等功能。局域网是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。

  广域网(Wide Area Network),简称WAN,是一种跨越大的、地域性的计算机网络的集合。通常跨越省、市,甚至一个国家。广域网包括大大小小不同的子网,子网可以是局域网,也可以是小型的广域网。

  两者区别:

  • 范围不同,广域网比局域网广
  • 接口类型不同
  • 速率不同
  • 协议不同

8、什么是socket?简述基于tcp协议的socket通信流程?

  • socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。
  • 通信流程:
    1. 服务端创建一个ServerSocket对象,指定端口号,ServerSocket对象等待客户端的连接请求。
    2. 客户端创建一个Socket对象,指定主机地址和端口号,向服务端发出连接请求。
    3. 服务端接收到客户端的连接请求,建立一条TCP连接,再创建一个Socket对象与客户端的Socket对象进行通信。
    4. 服务端和客户端分别创建字节输入流和字节输出流,通过字节输入流获得对方发来的数据,通过字节输出流向对方发送数据。
    5. 当一方决定结束通信时,向对方发送结束信息;另一方接收到结束信息后,双方分别关闭各自的TCP连接。
    6. ServerSocket对象停止等待客户端的连接请求。

9、什么是粘包?出现粘包的原因?

  • 粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
  • 出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。
    • 发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
    • 接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

  发生粘包现象如何处理?

  1. 对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;
  2. 对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;
  3. 由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。

10、IO多路复用的作用?

  I/O多路复用是用于提升效率,单个进程可以同时监听多个网络连接IO。

  与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

  select、poll、epoll

  select是windows提供的,poll和epoll是linux提供的,epoll最好。

  

  io多路复用:代理所有的网络对象,帮助我们监听有哪一个对象发生了注册事件(读\写\异常),然后通知程序,去进行相应的处理。

11、什么是防火墙?防火墙的作用是什么?

  • 在互联网上防火墙是一种非常有效的网络安全模型,通过它可以隔离风险区域(即Internet或有一定风险的网络)与安全区域(局域网)的连接,同时不会妨碍人们对风险区域的访问。所以它一般连接在核心交换机与外网之间。
  • 防火墙的作用:
    1. 过滤进出网络的数据 
    2. 管理进出访问网络的行为 
    3. 封堵某些禁止业务 
    4. 记录通过防火墙信息内容和活动 
    5. 对网络攻击检测和告警

12、select、poll、epoll模型的区别

  参考链接

  1. 支持一个进程所能打开的最大连接数
    • select的最大连接数大概3232,或者3264
    • poll本质和select没区别,但是它没有最大连接数限制
    • epoll大概10万左右(1G的机器)
  2. FD剧增后带来的IO效率问题
    • select和poll每次调用都会对连接进行线性遍历,所以会随着FD的增加会造成遍历速度慢的“线性下降性能问题”
    • epoll没有前两个的线性下降的性能问题,但是当socket都很活跃的情况下,可能会有性能问题。
  3. 消息传递方式
    • select和poll内核需要将消息传递到用户空间,都需要内核拷贝动作。
    • epoll通过内核和用户空间共享一块内存来实现

13、简述进程,线程,协程的区别以及应用场景?

  在正常的编程语言中:

    进程:是计算机中最小资源分配单位,数据隔离,开销(开启、销毁、切换)大,内存级别数据安全,但是文件操作\数据库操作等非内存级别的数据是不安全的,所以才有了进程锁。

    线程:计算机中能被cpu调度的最小单位,数据共享,开销(开启、销毁、切换)小,数据不安全,数据共享程序可能会同时操作一个变量。

    协程:数据共享,开销非常小(和函数的调用的速度一样快),数据绝对安全,协程本质是一条线程,协程任务对于操作系统来说不可见,协程是用户级的单位。

  在Cpython解释器下:

    进程:

    线程:不能利用多核,文件操作更快

      因为GIL锁:它是Cpython解释器下全局解释器锁,锁的是线程,保证了同一个进程中的多个线程之间,只有一个线程能访问cpu,限制了一个python进程中的多线程不能利用多核,无法处理高计算型的任务。解决方案:开多进程。

    协程:一条线程,指的是程序能够在多个协程任务之间来回切换,所以如果程序中遇到io就切换去执行另一个程序,实现了使用协程来规避io,执行cpu的使用率。所有time.sleep  socket 协程更快

      asyncio:基于yield关键字,内置模块

      gevent:基于greenlet来完成的,扩展模块

      aiohttp

    什么时候使用什么?哪些框架用什么?

      协程:tornado、twised、sanic、scrapy

      线程:flask,django

  区别:

    线程是资源分配的单位

    线程是操作系统调度的单位

    进程切换需要的资源很大,效率很低

    线程切换需要的资源一般,效率一般(在不考虑GIL的情况下

    协程切换任务资源很小,效率高

    多进程,多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发。)

  应用场景

    协程:当程序中存在大量不需要cpu的操作时,适用协程

    计算密集型,用进程。IO密集型,用线程。

  IPC(inter process communication):如队列、消息队列、redis、memcache

    管道:基于socket + pickle

    原生的queue:基于文件(管道 + 锁)

    第三方工具:基于网络\稳定性更强

14、什么是GIL锁

  • 即全局解释器锁。
  • 一个时间点只有一个线程处于执行状态。

15、python中如何使用进程池和线程池?

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import os,time,random
from multiprocessing import Pool

def task(n):
    print('%s is runing' %os.getpid())
    time.sleep(random.randint(1,3))
    return n**2
    
if __name__ == '__main__':
    # 多进程方式一
    pool2=Pool()
    pool2.map(task,range(10))
    
    # 多进程方式二,下面这种多进程和多线程的用法一模一样
    executor=ThreadPoolExecutor(max_workers=3)
    futures=[]
    for i in range(11):
        future=executor.submit(task,i)
        futures.append(future)
    executor.shutdown(True)
    print('+++>')
    for future in futures:
        print(future.result())

16、threading.local的作用

  • 为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。

17、进程之间如何进行通信?

  1. 共享内存
    • 通过mmap模块实现
  2. 信号
  3. 通过Queue队列
  4. 通过Pipe管道
  5. 通过socket

18、什么是并发和并行

  并发:不能利用多核,同一时间段内,有多个任务在一个CPU上轮流执行。指应用能够交替执行不同的任务,其实并发有点类似于多线程的原理,多线程并非是同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度不断去切换这两个任务,已达到"同时执行效果",其实并不是的,只是计算机的速度太快,我们无法察觉到而已.

  并行:能利用多核,同一时刻 有多个任务在CPU上同时执行。指应用能够同时执行不同的任务,

  并发是多个事件在同一时间段执行,并行是多个事件在同一时间点执行。

19、解释什么是异步非阻塞

  同步和异步:

    同步:当我执行一个任务,需要等待这个任务的结果才能执行下一个任务。就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

    异步:当我执行某一个任务,不需要等待这个任务的结果,就可以执行下一个任务。当一个异步过程调用发出后,调用者不会立刻得到结果。实际处理这个调用的部件是在调用发出后,通过状态、通知来通知调用者,或通过回调函数处理这个调用。

  阻塞和非阻塞:

    阻塞:CPU不工作。阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。

    非阻塞:CPU一直在工作。指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

    阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;

    同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。

  io操作(所有的输入[input]输出[output]都是针对内存的,内存里都是什么东西?可以理解成就是str或者bytes):

    input操作有:input、read、recv、recvfrom、accept、connect、close

    output操作有:write、send、sendto、accept、connect、close

  同步阻塞:

def func():
  import time
  time.sleep(1)

def func2():
  func()
  print(123)

func2()

  同步非阻塞:

def func():
  a = 1
  b = a + 1

def func2():
  func()
  print(123)

func2()

  异步阻塞:使用了多线程或者多进程

import time
import threading
def func():
    time.sleep(1)

t_l = []

for i in range(10):
    t = threading.Tread(target=func)
    t.start()
    t_l.append(t)

for t in t_l:
    t.join()

  异步非阻塞:我调用一个函数,不等待这个函数的结果,并且我能一直利用cpu。

20、路由器和交换机的区别

  • 交换机是一种用于电信号转发的网络设备。路由器是链接因特网中各局域网和广域网的设备。
  • 区别
    1. 交换机工作在第二层,数据链路层,路由器工作在第三层,网络层。
    2. 路由器提供防火墙服务。
    3. 传统交换机只能分割冲突域,不能分割广播域,而路由器可以分割广播域。

21、什么是域名解析

  • 域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站一种服务。IP地址是网络上标识站点的数字地址,为方便记忆,采用域名来代替IP地址标识站点地址。域名解析就是域名到IP地址的转换过程。

22、如何修改本地hosts文件

  • 进入c:\windows\system32\drivers\etc进行修改

23、生产者消费者模型的应用场景

  • 说明
    • 生产者只在仓库未满时进行生产,仓库满时生产者进程被阻塞;消费者只在仓库非空时进行消费,仓库为空时消费者进程被阻塞;
  • 应用场景:处理数据比较消耗时间,线程独占,生产数据不需要即时的反馈等。比如说写入日志,将多线程产生的日志放在队列中,然后写入。

24、什么是cdn

  • cdn全称是内容分发网络。其目的是让用户能够更快速的得到请求的数据。
  • cdn就是用来加速的,他能让用户就近访问数据,这样就更更快的获取到需要的数据。

29、traceroute使用哪种网络协议

  traceroute (Windows 系统下是tracert) 命令利用ICMP 协议定位您的计算机和目标计算机之间的所有路由器。

34、守护线程,守护进程是什么

  • 主进程创建守护进程
    1. 守护进程会在主进程代码运行结束的情况下,立即挂掉。
    2. 守护进程本身就是一个子进程。
    3. 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
  • 守护线程
    1. 守护线程会在"该进程内所有非守护线程全部都运行完毕后,守护线程才会挂掉"。并不是主线程运行完毕后守护线程挂掉。这一点是和守护进程的区别之处!
    2. 守护线程守护的是:当前进程内所有的子线程!
    3. 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。

36、简述多进程开发中join和deamon的区别

  • join:当子线程调用join时,主线程会被阻塞,当子线程结束后,主线程才能继续执行。
  • deamon:当子进程被设置为守护进程时,主进程结束,不管子进程是否执行完毕,都会随着主进程的结束而结束。

37、GIL锁对python性能的影响

  • 会降低多线程的效率。可以说python就是个单线程的程序。
  • 如何避免:
    • 用多进程代替多线程
    • 使用其他解释器

39、使用yield实现一个协程

def consumer():
    r = ''
    while True:
        n = yield r
        if n is None:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

40、使用async语法实现一个协程

import asyncio
import time

now = lambda : time.time()

async def hello():
    print("hello")
    await asyncio.sleep(2)
    return "done"
    
start = now()
# 协程对象
h1 = hello()
h2 = hello()
h3 = hello()

# 创建一个事件loop
loop = asyncio.get_event_loop()
# 任务(task)对象
tasks = [
asyncio.ensure_future(h1),
asyncio.ensure_future(h2),
asyncio.ensure_future(h3),
]

# 将协程加入到事件循环loop
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
    print(task.result())
    
print(now()-start)

41、简述线程死锁是怎么造成的。如何避免?

  • 死锁的产生原因?
    • 系统资源的竞争
    • 进程运行推进顺序不当
  • 解决死锁
    • 加锁顺序:线程按照一定的顺序加锁
    • 加锁时限:线程尝试获取锁的时候加上一定的时限,超过时限,则放弃对该锁的请求,并释放自己占有的锁。
    • 死锁检测

42、什么是asyncio

  • asyncio是并发的一种方式,是一个协程相关的库。也叫异步IO

43、什么是gevent

  • gevent是一个python网络框架,它为各种并发和网络相关的任务提供了整洁的API

44、什么是twisted框架

  twisted是用python实现的基于事件驱动的网络引擎框架

45、什么是LVS

  • LVS是linux虚拟服务器,是一个虚拟的linux集群系统。

46、什么是Nginx

  • nginx是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务

47、什么是keepalived

  • Keepalived是Linux下一个轻量级别的高可用解决方案

48、什么是haproxy?

  • HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理

49、什么是负载均衡?

  • 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
  • 负载均衡其意思就是分摊到多个操作单元上进行执行。

50、什么是rpc

  # 远程过程调用 (RPC) 是一种协议,程序可使用这种协议向网络中的另一台计算机上的程序请求服务

  #1.RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。

  #2.首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。

  #2.在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,

  #3.最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

51、什么是正向代理和反向代理?

  • 正向代理
    • 正向代理类似一个跳板机,代理访问外部资源。
    • 正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
    • 正向代理作用:
      • 访问原来无法访问的资源,如google 
      • 可以做缓存,加速访问资源
      • 对客户端访问授权,上网进行认证
      • 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
  • 反向代理
    • 反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器
    • 反向代理的作用:
      • 保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击
      • 负载均衡,通过反向代理服务器来优化网站的负载

53、各层协议

  应用层:HTTP、HTTPS、SSL、SMTP 邮件传输协议、FTP 文件传输协议

  传输层:TCP(三次握手和四次挥手、黏包)、UDP,端口信息,四层交换机,四层路由器

  网络层:ipv4、ipv6,路由器,三层交换机,网关地址,子网掩码

  数据链路层:arp(通过ip地址找mac地址),rarp(通过mac找ip地址),mac地址,交换机

  物理层

  tcp:可靠的,面向连接的,全双工的流式传输,正因为是流式传输,无边界,所以会有黏包现象。

  udp:可以理解为快递的包裹。

  黏包:解决黏包的方法,(自定义协议,也就是双方都知道的规定)先发送数据的长度,再发送数据

  arp协议:用到的设备是交换机,用到的通信手段是广播和单播,因为交换机不认识ip地址,认识mac地址,通过一次广播,一次单播完成一次请求。

  ipv4:四位的点分十进制

  ipv6:六位冒号分十六进制

  交换机是二层的,路由器是三层的,也有三层交换机(即带路由功能的交换机),也有四层路由器,四层交换机,它能直接帮我们找到对应的ip地址,对应的端口号。

54、手写socket

  # server - tcp

  import socket

  sk = socket.socket()

  sk.bind(('127.0.0.1', 9000))

  sk.listen(5)

  # while True  表示能够和多个socket通信

  conn,addr = sk.accept()   # 建立三次握手的过程

  # while True   表示能够和一个client说多句话

  conn.recv(1024)

  conn.send(b'xxx')

  conn.close()

  sk.close()

 

  # clinet - client

  import socket

  sk = socket.socket()

  sk.connect(('',9000))

  sk.send(b'hello')

  sk.recv(1024)

  sk.close()

 

  # server - udp

  import socket

  sk = socket.socket(type=socket.SOCK_DGRAM)

  sk.bind(('127.0.0.1',9000))

  while True:

    msg,cli_addr = sk.recvfrom(1024)

    sk.sendto(msg,cli_clent)

  sk.close()

 

  # client - udp

  import socket

  sk = socket.socket(type=socket.SOCK_DGRAM)

  sk.sendto(b'msg', ('127.0.0.1',9000))

  msg,_ = sk.recvfrom(1024)

  print(msg)

  sk.close()

 

posted @ 2019-02-03 11:09  勇敢的巨蟹座  阅读(196)  评论(0)    收藏  举报