zoukankan      html  css  js  c++  java
  • Python 使用socket实现一对多通信

    这个折磨了我快一天的时间,查看官网的socket入门例子,都是一对一的,服务器是处理一对一的形式。如果让服务器处理多个客户端,使用Python提供的socketserver函数和select也是可以解决的,但是这两个只能处理客户端发过来的信息,不能自动发起向已经连接到服务器的某个客户端进行通信,经过了多方的查找资料和总结,终于使用socket和threading解决了这个问题。

    服务器代码:

      

     1 from tkinter import *
     2 from socket import *
     3 import threading
     4 
     5 
     6 address='0.0.0.0'
     7 port=9000
     8 buffsize=1024
     9 s = socket(AF_INET, SOCK_STREAM)
    10 s.bind((address,port))
    11 s.listen(5)     #最大连接数
    12 conn_list = []
    13 conn_dt = {}
    14 
    15 def tcplink(sock,addr):
    16     while True:
    17         try:
    18             recvdata=sock.recv(buffsize).decode('utf-8')
    19             print(recvdata, addr)
    20             gui.infoList.config(state=NORMAL)
    21             gui.infoList.insert(END, addr, 'name')
    22             gui.infoList.insert(END, '')
    23             gui.infoList.insert(END, recvdata, 'conment')
    24             gui.infoList.insert(END, '
    
    ')
    25             gui.infoList.config(state=DISABLED)
    26             if not recvdata:
    27                 break
    28         except:
    29             sock.close()
    30             print(addr,'offline')
    31             _index = conn_list.index(addr)
    32             gui.listBox.delete(_index)
    33             conn_dt.pop(addr)
    34             conn_list.pop(_index)
    35             break
    36 
    37 def recs():
    38     while True:
    39         clientsock,clientaddress=s.accept()
    40         if clientaddress not in conn_list:
    41             conn_list.append(clientaddress)
    42             conn_dt[clientaddress] = clientsock
    43             gui.listBox.insert(END, clientaddress)
    44         print('connect from:',clientaddress)
    45         #在这里创建线程,就可以每次都将socket进行保持
    46         t=threading.Thread(target=tcplink,args=(clientsock,clientaddress))
    47         t.start()
    48 
    49 
    50 class GUI:
    51     def __init__(self, root):
    52         self.root = root
    53         self.leftFrame = Frame(self.root, width=20, height=30)
    54         self.leftFrame.grid(row=0, column=0)
    55         self.rightFrame = Frame(self.root, width=20, height=30)
    56         self.rightFrame.grid(row=0, column=1)
    57         Label(self.leftFrame, text='在线IP地址列表').grid(row=0, column=0)
    58         self.listBox = Listbox(self.leftFrame, width=15, height=10)
    59         self.listBox.grid(row=1, column=0)
    60         self.entry = Entry(self.rightFrame, font=('Serief', 18), width=30)
    61         self.entry.grid(row=0, column=0)
    62         self.sendBtn = Button(self.rightFrame, text='发送', command=self.send, width=10)
    63         self.sendBtn.grid(row=0, column=1)
    64         Label(self.rightFrame, text='聊天信息').grid(row=1, columnspan=2)
    65         self.infoList = Text(self.rightFrame, width=40, height=12)
    66         self.infoList.grid(row=2, columnspan=2)
    67         self.infoList.tag_config('name', background='yellow', foreground='red')
    68         self.infoList.tag_config('conment', background='black', foreground='white')
    69 
    70 
    71     def send(self):
    72         _index = self.listBox.curselection()
    73         conn_dt[self.listBox.get(_index)].sendall(self.entry.get().encode('utf-8'))
    74         self.entry.delete(0, END)
    75 
    76 def createGUI():
    77     global gui
    78     root = Tk()
    79     gui = GUI(root)
    80     root.title('服务器')
    81     root.mainloop()
    82 
    83 if __name__ == '__main__':
    84     t1 = threading.Thread(target=recs, args=(), name='rec')
    85     t2 = threading.Thread(target=createGUI, args=(), name='GUI')
    86 
    87     t1.start()
    88     t2.start()

    客户端代码:

      

     1 from socket import *
     2 import threading
     3 from tkinter import *
     4 
     5 address='127.0.0.1'   #服务器的ip地址
     6 port=9000
     7 buffsize=1024
     8 s=socket(AF_INET, SOCK_STREAM)
     9 s.connect((address,port))
    10 
    11 
    12 
    13 def recv():
    14     while True:
    15         recvdata = s.recv(buffsize).decode('utf-8')
    16         gui.listBox.insert(END, recvdata)
    17         print('
    ' + recvdata + '
    ')
    18 
    19 class GUI:
    20     def __init__(self, root):
    21         self.root = root
    22         self.listBox = Listbox(self.root)
    23         self.listBox.pack()
    24         self.entry = Entry(self.root)
    25         self.entry.pack()
    26         self.sendBtn = Button(self.root, text='发送', command=self.send)
    27         self.sendBtn.pack()
    28 
    29     def send(self):
    30         senddata = self.entry.get()
    31         s.send(senddata.encode())
    32 
    33 def createGUI():
    34     global gui
    35     root = Tk()
    36     gui = GUI(root)
    37     root.title('客户端')
    38     root.mainloop()
    39 
    40 if __name__ == '__main__':
    41     t1 = threading.Thread(target=recv, args=(), name='recv')
    42     t2 = threading.Thread(target=createGUI, args=(), name='gui')
    43 
    44     t1.start()
    45     t2.start()

    加上了界面,可以实现服务端与已连接的某个客户端进行通信,可以处理多个客户端的通信,

  • 相关阅读:
    RN8209校正软件开发心得(1)
    Chrome 31版本导出Excel问题
    ComBox选择
    网页设计的一般步骤
    .NET一套开发工具
    关于用sql语句实现一串数字位数不足在左侧补0的技巧
    python jieba模块详解
    python内置函数详细描述与实例演示
    Markdown的基本语法记录
    python configparser模块详解
  • 原文地址:https://www.cnblogs.com/liyang93/p/9117387.html
Copyright © 2011-2022 走看看