赞
踩
Server:
Client:
技术选型:
Golang使用包:
基本网络协议包 | net |
---|---|
定时器包(用于心跳检测) | time |
Python使用包:
多线程 | _thread |
---|---|
GUI | PyQT5 |
定时任务 | QTimer |
package main import ( "fmt" "net" "time" ) type UDPAddr struct { IP []byte Port int } var UDPServerLog = ` _ _ _____ _____ _____ | | | | __ \| __ \ / ____| | | | | | | | |__) | | (___ ___ _ ____ _____ _ __ | | | | | | | ___/ \___ \ / _ \ '__\ \ / / _ \ '__| | |__| | |__| | | ____) | __/ | \ V / __/ | \____/|_____/|_| |_____/ \___|_| \_/ \___|_| ` var Ip_port_Map = make(map[string]UDPAddr) var heartbeat = "" func main() { fmt.Println(UDPServerLog) // 1. 设置接收数据IP端口 listen, err := net.ListenUDP("udp", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 8977, }) fmt.Println("[Server Start] IP: ", listen.LocalAddr()) if err != nil { fmt.Println("listen failed, err:", err) return } defer listen.Close() // 1.1 心跳检测 go func() { for { timers_heartbeat := time.NewTimer(time.Minute) <-timers_heartbeat.C fmt.Println("发送心跳包:", Ip_port_Map) if len(Ip_port_Map) != 0 { for k , v := range Ip_port_Map { data := k + ":" + "AreYouOk" var addra *net.UDPAddr addra = &net.UDPAddr{IP: v.IP, Port: v.Port} _, err = listen.WriteToUDP([]byte(data), addra) if err != nil { fmt.Println("Write to udp failed, err: ", err) } // 休眠等待接收包 time.Sleep(500000000) if heartbeat != string(data[:6]) { delete(Ip_port_Map, string(data[:6])) fmt.Println(heartbeat, "用户不在线") } } } timers_heartbeat.Reset(1*time.Second) } }() // 主业务 for { var data [128]byte // 2. 接收数据 n, addr, err := listen.ReadFromUDP(data[:]) if err != nil { fmt.Println("read udp failed, err:", err) continue } // 3. 新上线用户加入Map及移除下线用户 go func() { if string(data[7:13]) == "OnLine" { Ip_port_Map[string(data[:6])] = UDPAddr{IP:addr.IP, Port:addr.Port} } else if string(data[7:14]) == "OffLine" { delete(Ip_port_Map, string(data[:6])) fmt.Println("用户下线:", string(data[:6])) } else if string(data[7:11]) == "ImOK" { heartbeat = string(data[:6]) } }() // 4. 收到数据发送OK go func() { data_OK := "OK" _, err = listen.WriteToUDP([]byte(data_OK), addr) if err != nil { fmt.Println("Write to udp failed, err: ", err) } }() // 5. 群发数据 go func() { fmt.Println() fmt.Println("群发ing.....") for _ , v := range Ip_port_Map { var addra *net.UDPAddr addra = &net.UDPAddr{IP: v.IP, Port: v.Port} _, err = listen.WriteToUDP([]byte(data[:n]), addra) if err != nil { fmt.Println("Write to udp failed, err: ", err) } } fmt.Println("群发结束.....") }() fmt.Println("当前在线用户:",Ip_port_Map) fmt.Printf("数据:%v 地址:%v 字节长度:%v\n", string(data[:n]), addr, n) } }
import sys, socket, random, _thread from PyQt5.Qt import * from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit, QTextEdit,QLabel, QApplication) from PyQt5.QtCore import QTimer BUFSIZE = 128 client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ip_port = ('127.0.0.1', 8977) # 1. 随机生成用户名 name = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz!@#$%&*123456789', 6)) print("用户名: " + name) data = name + ":" + "OnLine" string_data = "" try: client.sendto(data.encode('utf-8'), ip_port) data, server_addr = client.recvfrom(BUFSIZE) if data.decode('utf-8') == "OK": print('服务器在线!', data.decode('utf-8'), server_addr) except Exception: print('服务器离线请稍后尝试!') quit() class Example(QWidget): def __init__(self): global string_data super().__init__() self.initUI() def initUI(self): # 输入框 self.qle = QLineEdit(self) self.qle.move(170, 260) # 用户名显示 self.qla = QLabel(self) self.qla.move(60, 10) self.qla.setText("User name: " + name) # 聊天数据显示 self.lbl = QTextEdit(self) self.lbl.setReadOnly(True) self.lbl.setMinimumSize(485, 200) self.lbl.move(60, 40) # 发送消息按键 redb = QPushButton('发送', self) redb.setCheckable(True) redb.move(200, 300) # 下线退出 reclo = QPushButton('退出', self) reclo.setCheckable(True) reclo.move(380, 300) redb.clicked[bool].connect(self.onChanged) reclo.clicked[bool].connect(self.OffLine) self.setMaximumSize(600, 370) self.setMinimumSize(600, 370) self.setWindowTitle('UDP Client') self.setWindowFlags(Qt.WindowMinimizeButtonHint) self.setWindowIcon(QIcon('C:/Users/KAILIN/AppData/Local/Microsoft/Edge Beta/User Data/Default/Web Applications/_crx_ihmafllikibpmigkcoadcmckbfhibefp/Edge Feedback.ico')) self.show() # 初始化定时器 self.timers = QTimer(self) self.timers.timeout.connect(self.Data_look) self.startTimer() def startTimer(self): self.timers.start(1000) # 1000 单位是毫秒, 即1秒 def Data_look(self): # 消息显示 self.lbl.setText(string_data) self.lbl.adjustSize() # 滑动条显示最底下 self.lbl.verticalScrollBar().setValue(self.lbl.verticalScrollBar().maximum()) self.lbl.moveCursor(QTextCursor.End) def onChanged(self): if self.qle.text() == "": return # 消息拼接 data = name + ":" + self.qle.text() try: # 发送数据 client.sendto(data.encode('utf-8'), ip_port) except Exception: print('服务器离线请稍后尝试!') self.qle.clear() def OffLine(self): super(Example, self).close() data = name + ":" + "OffLine" try: client.sendto(data.encode('utf-8'), ip_port) except Exception: print("下线失败!") self.OffLine() def Server_data(threadName): global string_data print("接收服务器数据") while True: # 6. 接收服务器数据 data, server_addr = client.recvfrom(BUFSIZE) print(data.decode('utf-8')[7:]) if data.decode('utf-8') == "OK": print('服务器接收到数据!', data.decode('utf-8'), server_addr) elif data.decode('utf-8')[7:] == "ImOK": continue elif data.decode('utf-8')[7:] == "AreYouOk": try: heartbeat_data = name+":"+"ImOK" client.sendto(heartbeat_data.encode('utf-8'), ip_port) except Exception: print("心跳包发送失败!") continue elif data.decode('utf-8')[6:7] == ":": print('接收到群数据!', data.decode('utf-8'), server_addr) string_data += data.decode('utf-8') + "\n" else: string_data += "消息发送失败! " + "\n" print('消息发送失败!') if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() _thread.start_new_thread(Server_data, ("Server_data_Thread",)) sys.exit(app.exec_()) client.close()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。