• Python的网络编程socket模块


    (1)利用socket进行简单的链接

    Python里面的socket支持UDP、TCP、以及进程间的通信,socket可以把我们想要发送的东西封装起来,发送过去,然后反解成原来的样子,事实上网路通信可以理解成都是建立在socket之上,下面的代码是演示利用socket进行简单的链接

    #要成一次通信,至少要有两个人,也就是一个服务端,一个客户端
    
    
    #服务端
    '''必须先开启着,等待客户端来进行链接请求,
    所以自己要先有个地址,也就是IP,也要现有自己的端口,没有端口进不去'''
    
    
    import socket
    sk= socket.socket()#创建对象
    
    sk.bind(('127.0.0.1',9999,))#绑定IP和端口,以一个元组的方式传进去
    sk.listen(5)#在前面链接已经建立的情况下,后面最多让五个人等待
    while True:#让服务器端处于可以永远处于接受客户端请求的状态
    
        conn,address=sk.accept()
        print(conn,address)
    '''
    监听端口,等待以及接受客户端的请求,有可能会阻塞,主要功能是建立链接,以及接受客户端信息
    conn相当于双方建立的这个链接,之后互相的通信要依靠这个链接;
    address指的的对方的IP和端口
    '''
    

     下面是客户端代码

    #客户端
    import socket
    obj =socket.socket()
    '''相对于客户端,制定要链接谁就好了
    '''
    
    obj.connect(('127.0.0.1',9999,))#链接服务端
    obj.close()#链接之后关闭
    

      我们先让服务器端启动,然后再启动客户端,结果如图所示

    成功打印出了每次的链接,以及客户端的IP以及端口号

    (2)基于socket实现简单的传送消息

    #服务器端
    import socket
    sk= socket.socket()
    
    sk.bind(('127.0.0.1',9999,))#绑定IP和端口,以一个元组的方式传进去
    sk.listen(5)#在前面链接已经建立的情况下,后面最多让五个人等待
    while True:#让服务器端处于可以永远处于接受客户端请求的状态
    
        conn,address=sk.accept()#基于conn这个链接发送东西
        conn.sendall(bytes('终有一天你会成为Python爬虫工程师的',encoding='utf-8'))#Python3要用bytes类型,发送字节
        '''建立一次链接,服务器就发送这个字段'''
        print(conn,address)
    

      然后用是客户端代码

    #客户端
    import socket
    obj =socket.socket()
    '''相对于客户端,制定要链接谁就好了
    '''
    
    obj.connect(('127.0.0.1',9999,))#链接服务端
    '''
    客户端去链接服务端,如果服务器端没有返回消息给客户端,则客户端会一直
    在recv状态,一直等待服务器的消息
    '''
    result1= obj.recv(2014)#表示最多接收1024个字节,超过了下次接收、
    result2= str(result1,encoding='utf-8')
    print(result2)
    obj.close()#链接之后关闭
    

      当启动一次客户端建立一次链接,就会收到消息,结果如图

    (3)基于socket实现聊天机器人

    #服务器端
    import socket
    sk= socket.socket()
    
    sk.bind(('127.0.0.1',9999,))#绑定IP和端口,以一个元组的方式传进去
    sk.listen(5)#在前面链接已经建立的情况下,后面最多让五个人等待
    while True:#让服务器端处于可以永远处于接受客户端请求的状态
    
        conn,address=sk.accept()#基于conn这个链接发送东西
        conn.sendall(bytes('你好,链接已经建立',encoding='utf-8'))#Python3要用bytes类型,发送字节
        # '''建立一次链接,服务器就先发送这个字段'''
        while True:#让通信状态不中断
            ret_bytes = conn.recv(1024)
            ret_str = str(ret_bytes,encoding='utf-8')
            if ret_str =='q':#如果收到q,则终止链接
                break
            conn.sendall(bytes(ret_str+' 已收到该信息',encoding='utf-8'))
        #print(conn,address)
    

      下面是客户端代码

    #客户端
    import socket
    obj =socket.socket()
    '''相对于客户端,制定要链接谁就好了
    '''
    
    obj.connect(('127.0.0.1',9999,))#链接服务端
    '''
    客户端去链接服务端,如果服务器端没有返回消息给客户端,则客户端会一直
    在recv状态,一直等待服务器的消息
    '''
    
    result1= obj.recv(2014)#表示最多接收1024个字节,超过了下次接收、
    result2= str(result1,encoding='utf-8')
    print(result2)
    while True:
        data = input('请输入你要发送的内容:')
        if data == 'q':
            obj.sendall(bytes(data, encoding='utf-8'))
            print('链接断开')
            break
        else:
            obj.sendall(bytes(data,encoding='utf-8'))
            rec_byte = obj.recv(1024)#发了之后,接收信息
            rec_str = str(rec_byte,encoding='utf-8')
            print(rec_str)
    
    obj.close()#链接之后关闭
    

      结果如图所示

     (4)利用socket传送图片文件

    #服务器端
    import socket
    sk= socket.socket()
    
    sk.bind(('127.0.0.1',9999,))#绑定IP和端口,以一个元组的方式传进去
    sk.listen(5)#在前面链接已经建立的情况下,后面最多让五个人等待
    while True:#
        conn,address= sk.accept()
        conn.sendall(bytes('链接已建立,可以发送数据了',encoding='utf-8'))
        file_size = str(conn.recv(1024),encoding='utf-8')#接收文件大小
        print('接收的文件字节数:'+file_size)
        total_size = int(file_size)
        has_recv = 0#默认已接收了0个字节
        f = open('new1.png','wb')
        #先接收文件大小,再开始接收文件
        while True:
            if total_size ==has_recv:#如果已接收的文件大小与客户端发送的一样大,则表示已经接收完毕
                break
    
            data = conn.recv(1024)
    
            f.write(data)
            has_recv +=len(data)
        print('文件接收成功')
        f.close()
    

      下面是客户端

    #客户端
    import os
    import socket
    obj =socket.socket()
    
    
    
    obj.connect(('127.0.0.1',9999,))#链接服务端
    '''
    客户端去链接服务端,如果服务器端没有返回消息给客户端,则客户端会一直
    在recv状态,一直等待服务器的消息
    # '''
    #obj.sendall(bytes('你好',encoding='utf-8'))
    ret_bytes = obj.recv(1024)
    ret_str = str(ret_bytes,encoding='utf-8')
    print(ret_str)
    
    #发送文件大小
    size=os.stat('f.jpg').st_size#获取文件大小
    obj.sendall(bytes(str(size),encoding='utf-8'),)#文件大小的int型,要先转化为字符串
    with open('f.jpg','rb')as f:
        for line in f:
            obj.sendall(line)
    obj.close()
    

      结果如图

    (5)socket粘包问题

    发送文件需要依赖双方的缓冲区,就是我们先把文件写到缓冲区,然后再发送过去,
    但是我们一般不知道什么时候发过去,这容易造成粘包问题。例如上面的例子,客
    户端先发送文件大小,然后读文件写进缓冲区,假如文件读取特别快,第一次发送
    过去的可能既有文件大小又有文件内容,造成错误,这叫粘包,简而言之就是收到
    的信息比原本应收的多。

    那么怎么解决粘包问题呢,通过发送以及接收确认包,还是以上面的例子说明,客户
    在发送文件大小之后不要马上发送文件,先recv接收一下,等待服务器发送已收到文
    件大小的确认包之后,再读取文件、发送文件,这样文件的发送和之前数据的发送就
    完全独立开
    来了。

    #服务器端
    import socket
    sk= socket.socket()
    
    sk.bind(('127.0.0.1',9999,))#绑定IP和端口,以一个元组的方式传进去
    sk.listen(5)#在前面链接已经建立的情况下,后面最多让五个人等待
    while True:#
        conn,address= sk.accept()
        conn.sendall(bytes('链接已建立,可以发送数据了',encoding='utf-8'))
    
        file_size = str(conn.recv(1024),encoding='utf-8')#接收文件大小
        print('接收的文件字节数:'+file_size)
        total_size = int(file_size)
        has_recv = 0#默认已接收了0个字节
        conn.sendall(bytes('文件大小已收到,可以开始发送数据了',encoding='utf-8'))#解决粘包问题,已经收到了文件大小,后面就可以单独发文件了
        f = open('new1.png','wb')
        #先接收文件大小,再开始接收文件
    
        while True:
            if total_size ==has_recv:#如果已接收的文件大小与客户端发送的一样大,则表示已经接收完毕
                break
    
            data = conn.recv(1024)
    
            f.write(data)
            has_recv +=len(data)
        print('文件接收成功')
        f.close()
    

      下面是客户端

    #客户端
    import os
    import socket
    obj =socket.socket()
    
    
    
    obj.connect(('127.0.0.1',9999,))#链接服务端
    '''
    客户端去链接服务端,如果服务器端没有返回消息给客户端,则客户端会一直
    在recv状态,一直等待服务器的消息
    # '''
    #obj.sendall(bytes('你好',encoding='utf-8'))
    ret_bytes = obj.recv(1024)
    ret_str = str(ret_bytes,encoding='utf-8')
    print(ret_str)
    
    #发送文件大小
    size=os.stat('f.jpg').st_size#获取文件大小
    obj.sendall(bytes(str(size),encoding='utf-8'),)#文件大小的int型,要先转化为字符串
    ack_packet=obj.recv(1024)
    print(str(ack_packet,encoding='utf-8'))
    with open('f.jpg','rb')as f:
        for line in f:
            obj.sendall(line)
    obj.close()
    

      





  • 相关阅读:
    排序二——交换排序
    桥接模式 Bridge
    外观模式Facade(解耦)
    装饰模式和代理模式的区别
    代理模式 proxy
    装饰器模式 Decorator
    适配器模式
    android launcher-启动过程
    ubuntu 编译openwrt
    Eclipse Memory Analyzer tool(MAT)
  • 原文地址:https://www.cnblogs.com/xiaobeibei26/p/6443358.html
Copyright © 2020-2023  润新知