Python socket实现多对多全双工通信的方法

yipeiwu_com5年前Python基础

服务器:#server.py

#!/usr/bin/env python
#-*-coding:utf-8-*-
import sys
import struct#将字符串打包为二进制流进行网络传输
import select#
import signal#用于捕获中断信号
import cPickle#将python对象进行序列化:dumps将python对象序列化保存为字符串,loads与之相反
from socket import *
HOST = ''
def send(channel,*args):#发送数据
  buffer = cPickle.dumps(args)
  value = htonl(len(buffer))
  size = struct.pack("L",value)
  channel.send(size)
  channel.send(buffer)
def receive(channel):#接收数据
  size = struct.calcsize("L")
  size = channel.recv(size)
  try:
    size = ntohl(struct.unpack("L",size)[0])#socket.ntohl(参考:http://blog.csdn.net/tatun/article/details/7194973)
  except struct.error,e:
    return ''
  buf = ''
  while len(buf) < size:
    buf += channel.recv(size-len(buf))
  return cPickle.loads(buf)[0]#恢复python对象
 
class ChatServer(object):
  def __init__(self,PORT,backlog = 5):
    self.clients = 0
    self.clientmap = {}
    self.outputs = [] #Client会话列表
    self.server = socket(AF_INET, SOCK_STREAM)
    self.server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#重用套接字地址
    self.server.bind((HOST,PORT))
    self.server.listen(backlog)
    signal.signal(signal.SIGINT,self.signalhandler)#使用signal模块捕获中断操作 SIGINT中断进程(ctrl+c), SIGTERM 终止进程,SIGKILL杀死进程,SIGALRM 闹钟信号
 
  def signalhandler(self,signum,frame):#中断处理方法
    print "Shutting down server ..."
    for output in self.outputs:
      output.close()
    self.server.close()
 
  def get_client_name(self,client):
    info = self.clientmap[client]
    host,port,name = info[0][0],info[0][1],info[1]
    return ':'.join((('@'.join((name,host))),str(port)))
 
  def run(self):
    inputs = [self.server]
    print 'Waiting for connect...'
    while True:
      try:
        readable,writeable,execption = select.select(inputs,self.outputs,[])
      except select.error,e:
        break
      for sock in readable:
        if sock == self.server:#服务器端接收
          client,address = self.server.accept()
          print "Chat server: connected from",address
          self.clients += 1
          cname = receive(client)
          send(client,str(address[0]))
          inputs.append(client)
          self.clientmap[client] = (address,cname)
          msg = "(Connected : New Client(%d) from %s)\n"%(self.clients,self.get_client_name(client))
          message = "At present, only one of you is in the chat room!"
          if self.clients == 1:
            send(client,message)
          for output in self.outputs:
            send(output,msg)
          self.outputs.append(client)#将开始回话的client加入Client回话列表
 
        #elif sock == sys.stdin:
          #break
        else:
          try:
            data = receive(sock)
            if data:
              msg = '[' + self.get_client_name(sock)+ '] >> ' + data
              for output in self.outputs:
                if output!=sock:
                  send(output,msg)
            else:
              self.clients-=1
              sock.close()
              inputs.remove(sock)
              self.outputs.remove(sock)
              msg = '(Now hung up: Client from %s)'%self.get_client_name(sock)
              message = "At present, only one of you is in the chat room!"
              for output in self.outputs:
                send(output,msg)
              if self.clients == 1:
                send(self.outputs[0],message)
          except error,e:
            inputs.remove(sock)
            self.outputs.remove(sock)
    self.server.close()
if __name__ == "__main__":
    server = ChatServer(6004)
    server.run()
 

客户端:#client.py

#!/usr/bin/env python
#-*-coding:utf-8-*-
from server import send,receive
from socket import *
import sys
import select
import cPickle
import struct
import signal
 
class ChatClient(object):
  def __init__(self,name):
    self.name = name
    self.connected = False
    self.host = 'localhost'
    self.port = 6004
    try:
      self.sock = socket(AF_INET,SOCK_STREAM)
      self.sock.connect((self.host,self.port))
      self.connected = True
      send(self.sock,self.name)
      data= receive(self.sock)
      addr = data
    except error,e:#socket.serro
      print 'Failed to connect to chat server'
      sys.exit(1)
  def run(self):
    while True:
      try:
        readable,writeable,exception = select.select([0,self.sock],[],[])
        for sock in readable:
          if sock == 0:
            data = sys.stdin.readline().strip()
            if data:
              send(self.sock,data)
          else:
            data=receive(self.sock)
            if not data:
              print 'Client shutting down.'
              self.connected = False
              break
            else:
              sys.stdout.write(data+'\n')
              sys.stdout.flush()
      except KeyboardInterrupt:
        print 'Client interrupted'
        self.sock.close()
        break
if __name__ == "__main__":
  name = raw_input("Please input login name > ")
  client=ChatClient(name)
  client.run()

以上这篇Python socket实现多对多全双工通信的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持【听图阁-专注于Python设计】。

相关文章

Python实现的文本对比报告生成工具示例

Python实现的文本对比报告生成工具示例

本文实例讲述了Python实现的文本对比报告生成工具。分享给大家供大家参考,具体如下: 借助于difflib的功能,可以针对我们的使用情况进一步进行功能的聚合。我想要的功能是输入两个文件...

Pycharm2017版本设置启动时默认自动打开项目的方法

Pycharm2017版本设置启动时默认自动打开项目的方法

最新版本不同于旧版本的设置,网上检索一番方法都不适用。 新版的设置位置在“configure->setting->Appearance&Behavior->System...

Python入门之modf()方法的使用

 modf()方法返回两个项的元组x的整数小数部分。这两个元组具有相同x符号。则返回一个浮点数的整数部分。 语法 以下是modf()方法的语法: import math...

浅谈python中字典append 到list 后值的改变问题

看一个例子 d={'test':1} d_test=d d_test['test']=2 print d 如果你在命令行实践的话,会发现你改动的是d_test ,但是d 也跟着改变...

Python减少循环层次和缩进的技巧分析

Python减少循环层次和缩进的技巧分析

本文实例分析了Python减少循环层次和缩进的技巧。分享给大家供大家参考,具体如下: 我们知道Python中冒号和缩进代表大括号,这样写已经可以节省很多代码行数,但是可以更优化,尽可能减...