[Python专题学习]-python Socket网络编程

一.Socket简介

  Socket是什么?

  a.Socket是电脑网络中进程间数据流的端点

  b.Socket操作系统的通信机制

  c.应用程序通过Socket进行网络数据的传输

  Socket通信方式:Socket分为UDP和TCP两种不同的通信方式。

  为什么是Socket?

  a.Socket能够适应多种网络协议

  b.Socket是基础应用,了解Socket可以举一反三

  c.服务器传输大量涉及网络协议,离不开socket应用

 

二.Socket通信入门

   服务端程序socket_server.py

#导入模块
import socket

#创建实例
sk = socket.socket()
#定义绑定ip和port
ip_port = ("127.0.0.1", 8888)
#绑定监听
sk.bind(ip_port)
#最大连接数
sk.listen(5)
#提示信息
print("正在进行等待接受数据...")
#接受数据
conn, address = sk.accept()
#定义信息
msg = "Hello World!"
#返回信息
conn.send(msg)

   客户端程序socket_client.py

#导入模块
import socket

#实例初始化
client = socket.socket()
#访问的服务器端的IP和端口
ip_port = ("127.0.0.1", 8888)
#连接主机
client.connect(ip_port)
#接收主机信息
data = client.recv(1024)
#打印接收的数据
#此处的byte型数据特指python3.x以上
print(data.decode())

  先运行服务器端程序,会进入等待接受数据

  再运行客户端程序

  此时,可以看到服务器端的程序也结束运行了

 

三.socket客户端连续消息发送

  服务端:

#导入模块
import socket
import random

#创建实例
sk = socket.socket()
#定义绑定ip和port
ip_port = ("127.0.0.1", 8888)
#绑定监听
sk.bind(ip_port)
#最大连接数
sk.listen(5)
#不断循环,不断接受数据
while True:
    #提示信息
    print("正在进行等待接受数据...")
    #接受数据
    conn, address = sk.accept()
    #定义信息
    msg = "连接成功!"
    #返回信息
    #python3.x以上,网络数据的发送接受都是byte类型
    #如果发送的数据是str型的则需要进行编码
    conn.send(msg.encode())
    #不断接收客户端发来的消息
    while True:
        #接收客户端消息
        data = conn.recv(1024)
        #打印数据
        print(data.decode())
        #接收到退出指令
        if data == b'exit':
            break
        #处理客户端数据
        conn.send(data)
        #发送随机数信息
        conn.send(str(random.randint(1, 1000)).encode())
    #主动关闭连接
    conn.close()

  客户端:

#导入模块
import socket

#实例初始化
client = socket.socket()
#访问的服务器端的IP和端口
ip_port = ("127.0.0.1", 8888)
#连接主机
client.connect(ip_port)
#定义一个循环,不断的发送消息
while True:
    #接收主机信息
    data = client.recv(1024)
    #打印接收的数据
    #此处的byte型数据特指python3.x以上
    print(data.decode())
    #定义一个循环,不断的发送消息
    #输入发送的消息
    msg_input = input("请输入发送的消息:")
    #消息发送
    client.send(msg_input.encode())
    if msg_input == "exit":
        break
    data = client.recv(1024)
    print(data.decode())

  首先运行服务端,再运行先后运行两次客户端如下:

  但如果同时开启两个以上socket_client,则会报错,提示每个套接字地址只允许使用一次。这是因为当前的客户端和服务端正在进行通讯,是一种阻塞的状态,当下一个客户端进行连接的时候,它并不能直接马上进行通讯,所以报错了。

 

四.socket实例化参数含义

 

五.socket udp通信

  socket_server_udp.py

#导入模块
import socket

#创建实例
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#定义绑定的ip和port
ip_port = ("127.0.0.1", 8888)
#绑定监听
sk.bind(ip_port)
#不断循环接受数据
while True:
    #接收数据
    data = sk.recv(1024)
    #打印数据
    print(data.decode())

  socket_client_udp.py

#导入模块
import socket

#定义实例
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#定义需要连接的服务器的ip和port
ip_port = ("127.0.0.1", 8888)
#循环数据的输入
while True:
    #输入发送的信息
    msg_input = input("请输入发送的消息:")
    #退出循环条件
    if msg_input == "exit":
        break
    #数据发送
    sk.sendto(msg_input.encode(), ip_port)
#发送关闭信息
sk.close()

  先运行服务器端,再先后运行两次客户端:

  与TCP不同的是,UDP的通讯方式是可以进行多次数据发送以及多客户端的连接,因为UDP的通讯方式并不建立一个可靠的通信通道。UDP对于接收来的消息是否同一个客户端发送并不是特别的关心,因此对于多个客户端的连接,UDP服务器虽然没有一个特殊的定义,但是依然能够进行连接。

 

六.socket非阻塞模块

Socket的非阻塞

  平常的访问我们没有见到有阻塞的情况啊,python无法实现吗?如何解决阻塞呢?当然能够解决。

  socketserver这个模块可以同时多个客户端进行连接,即实现非阻塞的socket程序,主要是因为它使用了多线程的方式,每进行一次连接就会启一个线程,通过不断启线程的方式来达到与多个客户端连接的目的。它引用了socket、selectors、threading等模块,如下所示:

  BaseRequestHandler模块有四个方法,初始化方法和另外三个完全pass的方法,对于要使用socketserver模块的话,就要通过自已定义的类去对这三个方法进行定义,以覆盖原来的方法,这三个方法的执行顺序是setup、handle、finish。

 

   socket_server_tcp2.py

#导入模块
import socketserver
import random

#定义一个类
class MyServer(socketserver.BaseRequestHandler):
    #如果handle方法出现报错,则会进行跳过,setup方法和finish方法无论如何都会进行执行
    #一般情况下,我们只需去进行handle方法的书写

    #首先执行setup
    def setup(self):
        pass

    #然后执行handle
    def handle(self):
        #定义连接变量
        conn = self.request
        #发送消息定义
        msg = "Hello World!"
        #消息发送
        conn.send(msg.encode())
        #进入循环,不断接收客户端的消息
        while True:
            #接收客户端消息
            data = conn.recv(1024)
            #打印消息
            print(data.decode())
            #接收到exit则进行循环的退出
            if data == b'exit':
                break
            conn.send(data)
            conn.send(str(random.randint(1, 1000)).encode())
        conn.close()

    #最后执行finish
    def finish(self):
        pass

if __name__ == "__main__":
    #创建多线程实例
    server = socketserver.ThreadingTCPServer(("127.0.0.1", 8888), MyServer)
    #开启异步多线程,等待连接
    server.serve_forever()

  此时先运行socket_server_tcp2,再运行socket_client

  这样的服务器可以同时接收多个客户端的连接和消息处理。

  

七.文件上传下载

  socket用处:运维的时候经常遇见需要文件上传的情况。尤其是运维脚本中需要同时第三方软件没有命令行的时候。

  这时候我们可以自已实现。

  file_recv.py

#导入模块
import socket

#实例化
sk = socket.socket()
#定义连接ip和port
ip_port = ('127.0.0.1', 9999)
#绑定ip和port
sk.bind(ip_port)
#最大连接数
sk.listen(5)
#进入循环接收数据
while True:
    #等待客户端连接
    conn, address = sk.accept()
    #一直使用当前连接进行数据发送,直到结束标志出现
    while True:
        #打开文件等待数据写入
        with open("file", "ab") as f:
            #接收数据
            data = conn.recv(1024)
            if data == b'quit':
                break
            #写入文件
            f.write(data)
        #接收完成标志
        conn.send('success'.encode())
    #打印提示信息
    print('文件接收完成')
#关闭连接
sk.close()

  file_send.py

#导入模块
import socket

#实例化模块
sk = socket.socket()
#定义连接ip和port
ip_port = ('127.0.0.1', 9999)
#服务器连接
sk.connect(ip_port)
#文件上传
#打开文件
with open('socket_server_tcp2.py', 'rb') as f:
    #按每一段分割文件
    for i in f:
        #数据上传
        sk.send(i)
        #等待接收完成
        data = sk.recv(1024)
        #判断服务器是否真正的接收完成
        if data != b'success':
            break
#给服务器端发送结束信息
sk.send('quit'.encode())

  先运行服务端,再运行客户端,能正常实现文件的上传。

  我们可以看到file_recv.py的最后一行代码开发工具给我们标出了黄色,这里的关闭连接没有生效,因为我们上面是while True直接进入等待,我们可以在文件接收的时候,可以接收关闭的程序,将服务器的程序进行关闭的操作等等。 

 

文章来源:https://www.imooc.com/video/17673

posted on 2019-04-21 10:59  bijian1013  阅读(241)  评论(0)    收藏  举报

导航