zoukankan      html  css  js  c++  java
  • python 实现实时聊天

    Python3 socket编程,并与多线程实现最简单的聊天工具之一

    socket通讯必须有服务端和客户端

    创建服务端:

    【第一步】:先创建一个socket类型的对象s:

    s=socket.socket(familly,type)

    family参数可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(用于IPV4协议的TCP和 UDP)。

    type参数一般为SOCK_STREAM(流套接字)或者 SOCK_DGRAM(数据报文套接字),很少用SOCK_RAW(raw套接字)。可以简单的认为:

    SOCK_STREAM :能确保数据达到,用于发送文件数据。

    SOCK_DGRAM  :不能确保数据到达,用于局域网广播消息。

    SOCK_RAW        :需要自定义IP包,暂不解释。

    其实后面还有参数proto用来指明要接收的协议包?fileno参数大概是内存地址一类的东西?默认都不填。

    【第二步】:调用socket对象里的bind方法绑定IP和端口:

    s.bind((host,port))

    bind只有一个tuple(元组)类型的参数,host为客户端的ip,0.0.0.0表示任何ip,本地测试也可以用127.0.0.1,端口最好大于1024。

    【第三步】:设置监听数:

    s.listen( )

    参数填最大监听的连接数。

    【第四步】:accept方法接收客户端的连接:

    connect , address = s.accept( )

    无参数,程序进入阻塞模式直到有客户端连接,接收到连接后会返回一个元组形式的参数:connect为新产生的socket对象,address为客户端的ip。

    【第五步】:收发数据及关闭连接:

    必须使accept返回的新socket对象connect来收发数据,connect里的send和recv方法

    connect.send(" string ".encode('utf8'))

    connect.recv(size).decode('utf8')

    send方法在Python2里参数是字符串,在Python3里参数是二进制对象,所以必须先用encode('utf8')将字符串重新编码

    recv方法参数为读取的缓冲区大小size,与send方法同理,接收到数据后必须用decode('utf8')将数据解码成可读的字符串

    最后会话结束s.close()关闭连接

    创建客户端:

    【第一步】:先创建一个socket类型的对象s:

    s=socket.socket(familly,type)

    与服务端同理

    【第二步】:连接服务端:

    s.connect((host,port))

    host为服务端主机的ip,端口为服务端定义的端口。

    【第三步】:收发数据及关闭连接:

    与服务端同理的send和recv方法

    s.send()、s.recv()、s.close()

    具体代码(必须在CMD里运行,每次服务端或客户端仅能发送一条信息,if内代码可精简):

    服务端:

    1.  
      import socket
    2.  
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    3.  
      s.bind(("127.0.0.1",1234))
    4.  
      s.listen(2)
    5.  
      sock,addr=s.accept()
    6.  
      while True:
    7.  
      t=sock.recv(1024).decode('utf8') #服务端先接收信息
    8.  
      if t == "exit":
    9.  
      break
    10.  
      print(t)
    11.  
      t=input()
    12.  
      if t == "exit":
    13.  
      break
    14.  
      sock.send(t.encode('utf8'))
    15.  
      s.close()

    客户端:
    1.  
      import socket
    2.  
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    3.  
      s.connect(("127.0.0.1",1234))
    4.  
      while True:
    5.  
      t=input()
    6.  
      s.send(t.encode('utf8')) #客户端先发送信息
    7.  
      if t == "exit":
    8.  
      break
    9.  
      t=s.recv(1024).decode("utf8")
    10.  
      if t == "exit":
    11.  
      break
    12.  
      print(t)
    13.  
      s.close()


    由于input函数的阻塞作用,以上的代码发完一条信息,只能等待另一端的信息发过来才能继续发送。

    这时就要考虑将输入与接收分开来,将接收的函数(或方法)从主线程里抓出来丢到另一个线程里单独运行,为实现这一功能,必须引入多线程。

    多线程的使用别人的教程写得都太杂乱,什么select都来了……,其实很简单,Python里两句话搞定,需要import  threading

    接收的方法为recv,就把s.recv()写到其他函数里,然后主函数里让它自己跑起来:

    trd=threading.Thread(target=rec,args=(sock,))
    trd.start()

    target参数为需要跑起来的函数名,仅函数名,不需要括号,args为传递到target函数里的参数(元组类型),这里仅传入收发数据用的socket对象即可

    改良后的代码(须在CMD里运行):

    服务端:

    1.  
      import socket
    2.  
      import threading
    3.  
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    4.  
      s.bind(("127.0.0.1",9999))
    5.  
      s.listen(2)
    6.  
      sock,addr=s.accept()
    7.  
      true=True
    8.  
      def rec(sock):
    9.  
      global true
    10.  
      while true:
    11.  
      t=sock.recv(1024).decode('utf8') #函数的核心语句就一条接收方法
    12.  
      if t == "exit":
    13.  
      true=False
    14.  
      print(t)
    15.  
      trd=threading.Thread(target=rec,args=(sock,))
    16.  
      trd.start()
    17.  
      while true:
    18.  
      t=input()
    19.  
      sock.send(t.encode('utf8'))
    20.  
      if t == "exit":
    21.  
      true=False
    22.  
      s.close()

    客户端:
    1.  
      import socket
    2.  
      import threading
    3.  
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    4.  
      s.connect(("127.0.0.1",9999))
    5.  
      true=True
    6.  
      def rec(s):
    7.  
      global true
    8.  
      while true:
    9.  
      t=s.recv(1024).decode("utf8") #客户端也同理
    10.  
      if t == "exit":
    11.  
      true=False
    12.  
      print(t)
    13.  
      trd=threading.Thread(target=rec,args=(s,))
    14.  
      trd.start()
    15.  
      while true:
    16.  
      t=input()
    17.  
      s.send(t.encode('utf8'))
    18.  
      if t == "exit":
    19.  
      true=False
    20.  
      s.close()
  • 相关阅读:
    ansible自动化运维04
    ansible自动化运维03
    ansible自动化运维02
    ansible自动化运维01
    mysql innodb存储引擎和一些参数优化
    Mysql 数据库常用配置命令
    zabbix server3.4 使用mailx配置邮件报警
    32_redis cluster的核心原理分析:gossip通信、jedis smart定位、主备切换
    31_redis cluster的自动化slave迁移实现更强的高可用架构的部署方案
    30_redis cluster通过master水平扩容来支撑更高的读写吞吐+海量数据
  • 原文地址:https://www.cnblogs.com/ithairy/p/9365085.html
Copyright © 2011-2022 走看看