欢迎来到赛兔子家园

soket编程

socket编程

socket是基于C/S架构的,也就是说进行socket网络编程,需要编写两个py文件,一个服务端,一个客户端

Python中的socket通信逻辑(图片来自网络):

Python提供了两个级别访问网络服务:

  • 低级别的网络服务支持基于Socket,它提供了标准的BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
  • 高级别的网络服务模块SocketServer,它提供了服务器中心类,可以简化网络服务器的开发。

什么是Socket?

Socket又称套接字,应用程序通常通过套接字向网络发出请求或者响应网络的请求,使主机间或者一台计算机上的进程间可以通讯。

Socket()函数

Python中,我们用socket()函数来创建套接字,语法格式如下:

socket.socket(family=-1, type=-1, proto=-1)

参数

  • family:套接字家族可以使AF_UNIX或者AF_INET,默认为-1
  • type:套接字类型可以根据是面向连接还是非连接分为SOCK_STREAM或SOCK_DGRAM,默认为-1
  • protocl:一般默认为0

直接socket.socket(),则全部使用默认值。

Socket对象内置方法

注意事项:

  1. Python3以后,socket传递的都是bytes类型的数据,字符串需要先转换一下,string.encode()即可;另一端接收到的bytes数据想要转换字符串,只要bytes.decode()一下就可以。
  2. 在正常通信时,accept()和recv()方法都是阻塞。所谓的阻塞就是指程序会一直暂停,等待数据过来。

Socket编程思路:

 服务端:

  1. 创建套接字,绑定套接字到本地IP与端口:socket.socket),s.bind()
  2. 开始监听连接:s.listen()
  3. 进入循环,不断接受客户端的连接请求,并返回(conn,address)二元元组,其中conn是一个通信对象,可以用来接收和发送数据。address是连接客户端的地址。:s.accept()
  4. 接收传来的数据,或者发送数据给对方:s.recv(),s.sendall()
  5. 传输完毕后,关闭套接字:s.close()

客户端:

  1. 创建套接字,连接服务器地址:socket.socket),s.connect()
  2. 连接后发送数据和接收数据:s.sendall(),s.recv()
  3. 传输完毕后,关闭套接字:s.close()

 简单实例

服务器端:

tocket_server.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'tian'
__data__ = '2020/1/7 18:09'

import socket

ip_port = ('127.0.0.1',9999)
sk = socket.socket() #创建套接字
sk.bind(ip_port) #绑定服务器地址
sk.listen(5) #监听连接请求,超过后排队
print('启动socket服务,等待客户端连接...')
conn,address = sk.accept() #等待连接,此处自动阻塞,conn是通信对象,address连接客户端的地址,样式ip+端口
while True: #一个死循环,直到客户端发送exit的信号,才关闭连接 clinet_data = conn.recv(1024).decode()#接收信息 if clinet_data == 'exit': #判断是否退出连接 exit("通信结束") print("来自{0}的客户端向你发来消息:{1}".format(address,clinet_data)) conn.sendall('服务器端已经接收到你的消息'.encode())#回馈信息给客户端 conn.close() #关闭连接

客户端:

socket_clinet.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'tian'
__data__ = '2020/1/7 18:10'

import socket

ip_port = ('127.0.0.1',9999)
s = socket.socket() #创建套接字
s.connect(ip_port)  #连接服务器

while True:
    inp = input("请输入要发送的信息:").strip()
    if not inp:continue #防止输入空信息,导致异常退出
    s.sendall(inp.encode())#将输入的内容发送到服务器端
    if inp == 'exit': #如果输入的是exit,表示断开连接
        print("通信结束!")
        break
    server_reply = s.recv(1024).decode()#接收服务器端的返回
    print(server_reply)
s.close() #关闭连接

运行服务器端、客户端.py文件,进行测试。

默认情况下创建的是单进程单线程,同时只能处理一个客户端请求,如果实现多客户端请求,那么需要使用多线程。

实现多客户端请求

使用Python内置的threading模块,配合socket模块创建多线程服务器。客户端代码不需要修改,复制多一份.py。

tocket_server.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'tian'
__data__ = '2020/1/7 18:09'

import socket
import threading #导入线程模块

def link_handler(link,client):
    """
    该函数为线程需要执行的函数,负责具体的服务器和客户端之间的通信工作
    :param link: 当前线程处理的连接
    :param client: 客户端ip和端口信息,一个二元元组
    :return: None
    """
    print("服务器开始接收来自[{0}:{1}]的请求...".format(client[0],client[1]))
    while True:
        clinet_data = link.recv(1024).decode()
        if clinet_data == "exit":
            print("结束与[{0}:{1}]的通信...".format(client[0],client[1]))
            break
        print("来自[{0}:{1}]的客户端向你发来信息:{2}".format(client[0],client[1],clinet_data))
        link.sendall('服务器已经收到你的消息'.encode())
    link.close()

ip_port = ('127.0.0.1',9999)
sk = socket.socket() #创建套接字
sk.bind(ip_port) #绑定服务器地址
sk.listen(5) #监听连接请求
print('启动socket服务,等待客户端连接...')

while True: #一个死循环,直到客户端发送exit的信号,才关闭连接
    conn,address = sk.accept() #等待连接,此处自动阻塞
    t = threading.Thread(target=link_handler,args=(conn,address))
  t.start()

 客户端代码不变,复制多几份.py文件,打开进行测试;

 socketserver编程

上面使用socket和threading模块实现了一个简单的多线程服务器。在非正式环境,随便使用还可以。但是如果要在生产环境中使用,那就不行。

Python为了满足我们对多线程网络服务器的需求,提供了socketserver模块。socketserver在内部使用IO多路复用以及多线程/进程机场,实现了并发处理多个客户端请求的socket服务端。每个客户端请求连接的服务器时,socketserver服务端都会

创建一个【线程】或者【进程】专门负责处理当前客户端的所有请求。

使用ThreadingTCPServer使用的例子:

服务器端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'tian'
__data__ = '2020/1/8 11:37'

import socketserver


class MyServer(socketserver.BaseRequestHandler):
    """
    必须继承socketserver.BaseRequestHandler类
    """

    def handle(self):
        conn = self.request #request里封装了所有请求的数据
        conn.sendall('欢迎访问socketserver服务器!'.encode())
        while True:
            data = conn.recv(1024).decode()
            if data == 'exit':
                print("断开与{0}的连接!".format(self.client_address,))
                break
            print("来自{0}的客户端向你发来消息:{0}".format(self.client_address,data))
            conn.sendall(('已收到你的消息:{0}'.format(data).encode()))

if __name__ == '__main__':

    #创建一个多线程TCP服务器
    server = socketserver.ThreadingTCPServer(('127.0.0.1',9999),MyServer)
    print("启动socketserver服务器!")
    #启动服务器,服务器一直保持运行状态
    server.serve_forever()

客户端(与上面的没有怎么改变)

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.connect(ip_port)
# sk.settimeout(5)

data = sk.recv(1024).decode()

print('服务器端返回的:',data)
while True:
    inp = input('你:').strip()
    if not inp:continue
    sk.sendall(inp.encode())
    if inp == 'exit':
        print("谢谢使用,88!")
    data = sk.recv(1024).decode()
    print('服务器:',data)
sk.close()

备注:复制多几个客户端运行进行测试;

 

 

 

  

posted on 2020-01-08 12:28  赛兔子  阅读(289)  评论(0编辑  收藏  举报

导航