Python之socket_tcp

摘要:
1.1socket编程之tcp编程"""socket类型sock_stream面向连接的流套接字,默认值tcp协议sock_dgram无连接的数据报文套接字,udp协议"""importsockets=socket.socket()s.bind(('127.0.0.1',9999))#bind接受一个2元祖s.listen()"""Acceptaconnection.Thesocketmustbe

1.1socket编程之tcp编程

"""
socket类型
sock_stream 面向连接的流套接字,默认值 tcp协议
sock_dgram  无连接的数据报文套接字,udp协议
"""
import socket
s = socket.socket()
s.bind(('127.0.0.1',9999))  #bind接受一个2元祖
s.listen()
"""
Accept a connection. The socket must be bound to an address and listening for connections.
The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, 
and address is the address bound to the socket on the other end of the connection
"""
new_socker,info = s.accept() #只接受一个client请求,阻塞
data=new_socker.recv(1024)  #阻塞
print(data)
print(type(data))
new_socker.send('back {}'.format(data).encode())
s.close()  

例子

有阻塞就要尽量放到线程中去执行,不要影响主线程
importsocket
server =socket.socket()
server.bind(('127.0.0.1',9999))
server.listen()
'''建立一个client,socket连接之后,只能发一次数据
在accept出阻塞,需要建立第二个连接
'''
whileTrue:
    new_socket,ip =server.accept()
    data = new_socket.recv(1024)
    new_socket.send('ck test {}'.format(data).encode())

socket群聊实例

importsocket
importthreading

classChatTcpServer:
    def __init__(self,ip,port):
        self.ip =ip
        self.port =port
        self.cliets ={}
        #实例化就创建一个socket对象
        self.socket =socket.socket()
    defstart(self):
        self.socket.bind((self.ip,self.port))
        self.socket.listen()
        threading.Thread(target=self._accept,name="_aceept").start()

    def _accept(self):  #只开启一个accept线程,连接产生的new_socket负责和线程receive同信
        whileTrue:
            print('1~~~~~~~~~~~~~~~~~~~',threading.enumerate())
            new_socket,raddr = self.socket.accept()    #阻塞主线程,所以开启一个工作线程receive
            threading.Thread(target=self._receive,name="reveive",args=(new_socket,)).start()
            self.cliets[new_socket] =raddr
            print(self.cliets)
            print(type(self.cliets.keys()))

    def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程
        whileTrue:
            print('2~~~~~~~~~~~~~~~~~~~',threading.enumerate())
            data = new_socket.recv(1024)               #阻塞
            for k inself.cliets.keys():
                k.send('ack {}'.format(data).encode())

    defstop(self):
        for s inself.cliets.values():
            s.close()
        self.socket.close()


if __name__ == '__main__':
    cs = ChatTcpServer('127.0.0.1',9999)
    cs.start()
    #print('3~~~~~~~~~~~~~~~~~~~',threading.enumerate())
    #cs.stop()
problem:there has a error when cliens exit
ConnectionAbortedError
importsocket
importthreading

classChatTcpServer:
    def __init__(self,ip,port):
        self.ip =ip
        self.port =port
        self.cliets ={}
        #实例化就创建一个socket对象
        self.socket =socket.socket()
        self.event =threading.Event()
    defstart(self):
        self.socket.bind((self.ip,self.port))
        self.socket.listen()
        threading.Thread(target=self._accept,name="_aceept").start()

    def _accept(self):  #只开启一个accept线程,连接产生的new_socket负责和线程receive同信
        while notself.event.is_set():
            new_socket,raddr = self.socket.accept()    #阻塞主线程,所以开启一个工作线程receive
            threading.Thread(target=self._receive,name="reveive",args=(new_socket,)).start()
            self.cliets[new_socket] =raddr
            print(self.cliets)
            print(type(self.cliets.keys()))

    def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程
        while notself.event.is_set():
            data = new_socket.recv(1024)               #阻塞
            for k inself.cliets.keys():
                k.send('ack {}'.format(data).encode())

    defstop(self):
        ifself.cliets:
            for s inself.cliets.values():
                s.close()
        self.socket.close()
        self.event.set()


if __name__ == '__main__':
    cs = ChatTcpServer('127.0.0.1',9999)
    cs.start()
    whileTrue:
        cmd = input("please set stop:>>>")
        if cmd == 'quit':
            cs.stop()
            break
以上版本服务端可以断开连接,但是客户端断开连接抛出异常 

增加客户端断开命令

客户端主动断开连接的问题,服务端知道自己何时断开
如果是客户端断开服务器不知道,所有好的做法客户端发出特殊消息通知服务器断开连接,但是客户端主动断开服务端主动发送一个空消息,超时返回异常,捕获异常并清理连接,即使为客户端提供了断开命令,也不能保证客户端会使用它断开连接,还是要增加这个退出功能
    def _receive(self,new_socket): #客户端连接几个socket 就开几个receive线程
        while notself.event.is_set():
            data = new_socket.recv(1024)               #阻塞
            if data == b"quit":
                self.cliets.pop(new_socket)
                new_socket.close()
                break
            for k inself.cliets.keys():
                k.send('ack {}'.format(data).encode())

socket常用方法

socket = socket.socket()
socket.recv(1024) bufsize=1024 获取数据,默认是阻塞状态
socket.recvfrom(1024)   获取数据,返回一个二元组(bytes,address)
socket.recv_into(buffer=1024,nbytes=10,flags=None) 获取到nbytes的数据后,存储到buffer中,如果nbytes没有指定或者0,将buffer大小的数据存入buffer中,返回接收的字节数
socket.send(bytes)  tcp发送设备
socket.sendall(bytes)   tcp发送全部设备,成功返回None

Makefile

socket.socket().makefile(mode='r',buffering=None)   创建一个与该套接字相关联的文件对象,将recv方法看作读方法,将send方法看作写方法
socket.getpeername()    返回连接套接字的远程地址,返回值通常是元组(ipaddr,port)
sockete.getsockname()    返回套接字自己的地址,通常是一个元祖(ipaddr,port)
socket.setbloking(flag)    如果flag为0则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)
非阻塞模式下,如果调用recv没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常
socket.settimeout(value)    设置套接字操作的超时期,timeout是一个浮点数单位秒
值为none表示没有超时期,一般超时期应该在刚创建套接字时设置,因为他们可能用于连接的操作(connect())

read和readline(行读取,包括换行符)

importsocket
socket =socket.socket()
socket.bind(('127.0.0.1',9999))
socket.listen()

whileTrue:
    new_socket,raddr =socket.accept()
    f = new_socket.makefile('rw')
    print(f)
    line = f.readline()  #Read and return one line from the stream
    line = f.read(10)   #Read up to n bytes from the object and return them
    #只有输入十个字节才会return
    print(line)
    f.write('ack {}'.format(line))
    f.flush()
f.close()

client编写

importsocket
socket =socket.socket()
socket.bind(('127.0.0.1',9999)) #server ip
socket.listen()

new_socket,raddr =socket.accept()
data = new_socket.recv(1024)
print(data)
new_socket.send('ack {}'.format(data).encode())
importsocket
importthreading
importdatetime
importlogging

FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'logging.basicConfig(level=logging.INFO,format=FORMAT)

classChatClient:
    def __init__(self,ip='127.0.0.1',port=9999):
        self.ip =ip
        self.port =port
        self.sock =socket.socket()
        self.event =threading.Event()

    defstart(self):
        self.sock.connect((self.ip,self.port))
        self.send('i am ready')
        threading.Thread(target=self.receive,name='receive').start()


    defreceive(self):
        while notself.event.is_set():
            try:  #连接不成功,捕获异常
                data = self.sock.recv(1024)
                logging.info(data)
            exceptException as e:
                logging.info(e)

    defsend(self,msg:str):
        self.sock.send('{}'.format(msg).encode())


    defstop(self):
        self.sock.close()
        self.event.set()
        logging.info('Client stops')

defmain():
    cc =ChatClient()
    cc.start()
    whileTrue:
        cmd = input("please set a number:")
        if cmd.strip() == b'quit':
            cc.stop()
            breakcc.send(cmd)

if __name__ == '__main__':
    main()

免责声明:文章转载自《Python之socket_tcp》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇jqweui 正在加载样式的用法MFC执行过程详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

tensorflow 保存训练模型ckpt 查看ckpt文件中的变量名和对应值

  TensorFlow 模型保存与恢复一个快速完整的教程,以保存和恢复Tensorflow模型。在本教程中,我将会解释: TensorFlow模型是什么样的? 如何保存TensorFlow模型? 如何恢复预测/转移学习的TensorFlow模型? 如何使用导入的预先训练的模型进行微调和修改? 这个教程假设你已经对神经网络有了一定的了解。如果不了解的话...

Spark python集成

Spark python集成 1、介绍 Spark支持python语言,对于大量的SQL类型的操作,不需要编译,可以直接提交python文件给spark来运行,因此非常简单方便,但是性能要比scala或java慢。对于常规任务,可以使用python来编写,特殊任务还是建议scala编写。 2、使用pyspark启动spark shell(centos) 2...

Python CRM项目八

自定义用户认证 目的:实现Django自定义的认证系统,在生产环境都是根据此代码进行定制的 步骤: 1.在settings文件中配置要使用的类 #命名规则 app名称.类名 AUTH_USER_MODEL = 'crm.UserProfile' 2.在crm app下的models文件中加入Django官方的用户...

Python 相对导入attempted relative import beyond top-level package

ValueError: attempted relative import beyond top-level package 假设有如下层次包目录 1 project/ 2 __init__.py 3 mypackage/ 4 __init__.py 5 A/ 6 __ini...

《篡权的ss》linux命令五分钟系列之三十一

原文链接 本原创文章属于《Linux大棚》博客。 博客地址为http://roclinux.cn。 文章作者为roc。 === 上篇文章《和netstat说再见》中说到netstat已经被抛弃,取而代之的是ss命令。一些朋友在问“netstat为什么会被抛弃呢?ss又是什么命令呢?” 这篇文章,我们就来揭晓答案,重点说一说“篡权的ss”。 【作者粗心大意?...

Python实现快捷输入(类似WeGame的一键喊话)

故事背景:   表弟跟我说,他玩游戏玩的不是很好,导致经常被队友互动,但是自己的手速有限,经常在互动中败阵。   因此,尝试做一款小工具,帮助表弟取得和队友互动的胜利! 逻辑设计:   监听键盘上的某个按键   当该按键被按下时,调用数据库(或者远程接口)的数据   将获取到的数据写进Windows的剪贴板   模拟粘贴快捷键(Ctrl + V),将数据文...