2019-10-27

2019-12-01  本文已影响0人  剑飞张

title: python socket编程入门
date: 2019-12-01 17:11:26
tags:


[toc]

socket

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。

基本上,Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入 http://www.cnblogs.com/ 时,你会打开一个套接字,然后连接到 http://www.cnblogs.com/ 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如 QQ 和微信也是类似。任何网络通讯都是通过 Socket 来完成的。<del>(从操作系统角度来看,socket 比进程的 pid 级别还低,socket 是识别进程通信间的进程,pid 是识别所有进程)<del>

socket和file的区别:

1、file模块是针对某个指定文件进行【打开】【读写】【关闭】

2、socket模块是针对 服务器端 和 客户端 Socket 进行【打开】【读写】【关闭】

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket 其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

socket

工作原理(流程)

工作流程

可以看到服务端必须先运行等待客户端连接。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞(阻塞这个进程),等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

python 的 socket 模块

Python 的 socket 模块提供了使用 Berkeley sockets API 的接口。

主要学习了以下 API:

Python 提供了和 C 语言一致且方便的 API。

tcp socket

tcp 是一个可靠的,有序的协议。网络总是会尽最大的努力去传输完整数据(往往不尽人意)。

网络设备(比如:路由器、交换机)都有带宽限制,或者系统本身的极限。它们也有 CPU、内存、总线和接口包缓冲区,就像我们的客户端和服务器。TCP 消除了对于丢包、乱序以及其它网络通信中通常出现的问题的顾虑。


tcp 工作的流程

左边表示服务器,右边表示客户端。

客户端调用 connect() 方法来建立与服务器的链接,并开始三次握手。握手很重要是因为它保证了网络的通信的双方可以到达,也就是说客户端可以正常连接到服务器,反之亦然。

上图中间部分往返部分表示客户端和服务器的数据交换过程,调用了 send() 和 recv()方法。

import socket

HOST = '127.0.0.1'  # 标准的回环地址 (localhost)
PORT = 65432        # 监听的端口 (非系统级的端口: 大于 1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

调用 socket() 时传入的 socket 地址族参数 socket.AF_INET 表示因特网 IPv4 地址族,SOCK_STREAM 表示使用 TCP 的 socket 类型,协议将被用来在网络中传输消息。

listen() 方法有一个 backlog 参数。它指定在拒绝新的连接之前系统将允许使用的 未接受的连接 数量。从 Python 3.5 开始,这是可选参数。如果不指定,Python 将取一个默认值。很明显,backlog起保护作用,防止服务器过载。

accept() 方法阻塞并等待传入连接。当一个客户端连接时,它将返回一个新的 socket 对象,对象中有表示当前连接的 conn 和一个由主机、端口号组成的 IPv4/v6 连接的元组。和监听一个 socket 不同的是后者只用来授受新的连接请求,而 accept() 则是得到一个新的 socket 对象。

import socket

HOST = '127.0.0.1'  # 服务器的主机名或者 IP 地址
PORT = 65432        # 服务器使用的端口

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b'Hello, world')
    data = s.recv(1024)

print('Received', repr(data))

与服务器程序相比,客户端程序简单很多。它创建了一个 socket 对象,连接到服务器并且调用 s.sendall() 方法发送消息,然后再调用 s.recv() 方法读取服务器返回的内容并打印出来。

运行结果:


简单tcp编程结果

udp socket

使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,不保证数据的一定到达。

虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.bind(('127.0.0.1',8080))
    while True:
        conn,addr = s.recvfrom(1024)
        print('Received from %s:%s.' % addr)
        s.sendto(b'Hello, %s!' % conn, addr)

UDP 的服务端仅需要监听端口的数据,而不需要监听是否会有新的连接请求,只需要数据来临就接收。

import socket

with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s:
    for data in [b'Michael', b'Tracy', b'Sarah']:
        s.sendto(data, ('127.0.0.1', 8080))
    # 接收数据:
        print(s.recv(1024).decode('utf-8'))

而 UDP 的客户端更加简单,只需要拿到数据之后往服务器地址的端口直接发送就行。

上一篇下一篇

猜你喜欢

热点阅读