socket 以及 Python 实现

作者: 一块大番薯 | 来源:发表于2018-04-13 20:54 被阅读15次

2018.04.14

由于 TCP 协议非常复杂,三次握手、累积确认、分组缓存这些应该是属于操作系统内核的部分, 没必要重复开发。操作系统抽象出一个概念,让上层应用去编程。这个概念就是 socket

一个完整的 socket 可以看成 (网络层协议,运输层协议, 客户端 IP, 客户端 Port, 服务器 IP, 服务器 Port)

UDP

recvfrom 返回的数据和地址。
sendto 的参数也是数据和地址。

# 服务器
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('localhost', 8888))
while True:
    data, addr = s.recvfrom(1024)
    print('Received from {}, data: {}'.format(addr, data.decode('utf-8')))
    s.sendto(b'Hello!', addr)
# 客户端
import socket

c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.sendto(b'good!', ('localhost', 8888))
data = c.recv(1024)
print(data.decode('utf-8'))

TCP

比 UDP 多了客户端连接,服务器监听,三次握手。

客户端

import socket

clientfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientfd.connect(('localhost', 8888))
data = clientfd.recv(1024)
print('Received: ' + data.decode('utf-8'))
clientfd.send(b'Haved Received!')

服务器

import socket

listenfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listenfd.bind(('localhost', 8888))
listenfd.listen()

while True:
    sock, addr = listenfd.accept()
    print('Connected to {}'.format(addr))
    sock.send(b'Hello, socket!')
    data = sock.recv(1024)  
    print('Received: ' + data.decode('utf-8'))
  • 这个 aceept 不简单,它与客户端的 connect 完成了三次握手。
  • 发送的数据是 bytes 型,接受后要解码。
  • sock 才是一个完整的 socket,而 clientfd 与 listenfd 都只是半个 socket。
  • listenfd 一般占用 80 端口(http 协议),每个客户端共享服务器这个端口,而每个连接(也就是程序中的 sock)依靠客户端的 IP 和 port 标识。

这是最原始的服务器,它有个严重的弊端:recv 方法,如果客户端一直没有发数据过来,服务器就一直阻塞(block)在那里,于是多进程并发编程出现了。

多进程

思路:当 accept 连接后,创建的新 socket 不在主进程中处理,而是新创建一个子进程进行托管,主进程只负责监听 80 端口、接受连接请求、创建子进程处理。也就是 recv 的锅,accept 来背,哈哈。

但是进程很多,每个进程都消耗大量的系统资源,况且进程间切换也是一笔大消耗。而一个 socket 就是一个文件描述符,是个整数,背后是一个简单的数据结构,用非常重量级的进程来对一个简单的数据结构进行读写,有点杀鸡用牛刀了!于是 select 模型诞生了!

select 模型

缕一缕前面:有两样东西,一个是 http server,另一个是操作系统,多进程是指 http server 占据操作系统的多个进程,并且每个进程遇到 recv 不到数据时就会阻塞。

select 模型思路:现在还是只有 http server 和操作系统,但是现在 http server 只占据操作系统的一个进程。http server 把所有 socket 的 fd (文件描述符)交给操作系统,然后阻塞。虽然还是阻塞,但是现在只是单进程。而操作系统在后台检查这些编号的 socket,如果发现有 socket 可以读写,就把这个 socket 打个标记,然后唤醒 http server,http server 就会遍历所有的 socket,哪个有标记就处理哪个。

但是,很多时候,活跃的 socket 只占少部分,而 http server 不得不遍历所有的 socket,这个不太好。最好的方式就是操作系统直接告诉 http server 哪些 socket 可以读写了,这样 http server 连遍历都不用了,这种方案就叫 epoll 。

epoll 模型

Nginx 采用的就是 epoll 模型,而 Apache 采用的是 select 。

相关文章

  • socket 以及 Python 实现

    2018.04.14 由于 TCP 协议非常复杂,三次握手、累积确认、分组缓存这些应该是属于操作系统内核的部分, ...

  • day19

    socket套接字 socket又叫套接字,实现网络通信的python通过提供socket标准库来支持socket...

  • socket编程

    python实现socket编程 实现的主要过程是: tcp server: tcp client 函数 的实现原型:

  • Python与Java之间Socket通信

    python socket server python socket client java socket cli...

  • python实现tcp协议的服务端与客户端

    服务端(server) python使用socket实现tcp协议的服务端,有以下几个步骤 创建socket 绑定...

  • ios socket笔记

    主要是有以上三个函数来实现socket开启,传输接收数据以及关闭socket

  • Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通...

  • web框架本质

    来个简单的socket服务端 上述通过socket来实现了其本质,而对于真实开发中的python web程序来说,...

  • 3. python多进程实现socket服务

    用python的multiprocessing.Process实现简单的socket服务 client.py se...

  • 构造icmp包python-socket-收包解包

    socket收包,如前面的文章实现了python socket发ping包,并且收到了对端的返回结果,那么如何把返...

网友评论

    本文标题:socket 以及 Python 实现

    本文链接:https://www.haomeiwen.com/subject/gutqkftx.html