分类
Python学习

python实现socket通信

python可以用来实现两个主机进程之间的TCP通信,就是通过使用socket套接字来实现的,我们可以基于此,来实现一些应用层协议,以达到不同主机之间的进程通信的目的。这一点,除了普通的网络应用程序(如聊天工具和游戏等)之外,在分布式系统中,也有着很大的用途,比如机器学习需要在多台计算机中进行并行计算的时候。

服务器/客户机模型(C/S模型)如图:

TCP服务器/客户端模型

关于服务器模型

服务器模型主要有以下这两种:

1 循环服务器

即在任一时刻只处理一个客户机的请求,处理该请求的过程中,下一请求处于等待状态。

优点是节省服务器资源,缺点是响应时间长,适合处理非耗时的请求。

2 并发服务器

即并发执行,服务器每收到一个连接请求就创建一个进程(或线程)处理该连接,服务器继续等待下一连接。

优点是响应速度快,缺点是占用系统资源多。

演示实例:

多进程TCP并发服务

我们要使用到的包是socket和multiprocessing

服务器端:

首先使用socket对象的socket()方法获取一个套接字对象,再使用bind()方法绑定服务器端的IP地址和端口号,接着调用listen()方法开始监听,使用阻塞式的accept()方法获取每一个传入的客户端连接对象conn和信息。

当每收到一个客户端连接后,我们就创建一个进程来专门处理这个客户端连接,在python中可以将要创建进程的类从multiprocessing.Process父类中继承,在子类中的__init__()函数里传入启动进程时用到的参数并初始化配置,在run()函数中处理相关事情,在父进程中使用start()方法启动这个进程。

对于客户端的连接对象conn可以使用settimeout()方法设置超时时间,使用recv()方法接收客户端发来的数据,作为回应,可以使用sendall()方法回应客户端,给客户端发数据。

当我们不再需要客户端的时候,服务器端可以使用close()方法关闭该连接。

import multiprocessing
import socket

class ClientProcess(multiprocessing.Process):
    def __init__(self,conn,addr):
        multiprocessing.Process.__init__(self)
        self.conn = conn
        self.addr = addr

    def run(self):
        self.conn.sendall(bytes("你好,我是AI柠檬~",encoding="utf-8"))
        ret_timeout = str(self.conn.recv(1024),encoding="utf-8")
        self.conn.settimeout(int(ret_timeout))
        
        while(True):
            try:
                ret = str(self.conn.recv(1024),encoding="utf-8")
                self.conn.sendall(bytes("我收到了你的信息:"+ret,encoding="utf-8"))
                if(ret==":q"):
                    self.conn.close()
                    break
            except Exception as ex:
                self.conn.close()
                break


if __name__ == '__main__':
    s = socket.socket()
    inp_addr = input("Please input this server's ip address:\n>>>")
    inp_port = input("Please input this server's port:\n>>>")
    s.bind((inp_addr,int(inp_port)))
    s.listen()
    print("服务器已开启")
    users = []
    while(True):
        conn,addr=s.accept()
        
        p = ClientProcess(conn,addr)
        p.start()
        users.append(p)
        print("有一个新用户连接,进程号pid:", p.pid)
        num = 0
        
        tmp_users=[]
        for i in range(len(users)):
            
            if(users[i].is_alive()==True):
                tmp_users.append(users[i])
            
        users = tmp_users
        print("当前用户数:", len(users))
    s.close()

客户端:

同样,首先先使用socket对象的socket()方法获取一个套接字对象,然后使用connect()方法连接到指定IP地址和端口的服务器端程序。

其他如同服务器端,使用sendall()方法写出数据,使用settimeout()方法设置超时时间,使用recv()方法接收服务器端发来的数据。

当我们不再需要服务器端的时候,客户端可以使用close()方法关闭该连接。

import socket

obj = socket.socket()

inp_addr = input("Please input server's ip address:\n>>>")
inp_port = input("Please input server's port:\n>>>")
obj.connect((inp_addr,int(inp_port)))

inp_timeout = input("Please input timeout(s):\n>>>")
obj.sendall(bytes(inp_timeout,encoding="utf-8"))
obj.settimeout(int(inp_timeout))

msg = str(obj.recv(1024),encoding="utf-8")
print(msg)

while True:
    inp = input("Please(:q\退出):\n>>>")
    if(inp!=""):
        obj.sendall(bytes(inp,encoding="utf-8"))
    if(inp == ":q"):
        obj.close()
        break
    try:
        ret = str(obj.recv(1024),encoding="utf-8")
        print(ret)
    except socket.timeout:
        print("[Error]Network Connection Time Out!")
        break
    except:
        print("[Error]Unknown Network Connection Error!")
        break


通过以上代码,就实现了不同主机上两进程间的socket套接字的TCP通信。由于Python的高度封装特性,我们所能做的很难涉及到底层,而且一般情况下也不需要涉及底层,除非我们有特殊需求。至于在做分布式的机器学习训练程序的设计和编程方法,就不是本文应该涉及的啦。

版权声明
本博客的文章除特别说明外均为原创,本人版权所有。欢迎转载,转载请注明作者及来源链接,谢谢。
本文地址: https://blog.ailemon.net/2018/01/21/python-implement-about-socket-connection/
All articles are under Attribution-NonCommercial-ShareAlike 4.0

关注“AI柠檬博客”微信公众号,及时获取你最需要的干货。


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

4 × 2 =

如果您是第一次在本站发布评论,内容将在博主审核后显示,请耐心等待