色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術文章
文章詳情頁

python Socket網絡編程實現C/S模式和P2P

瀏覽:13日期:2022-07-20 08:20:21

C/S模式

由于網絡課需要實現Socket網絡編程,所以簡單實現了一下,C/S模式分別用TCP/IP協議與UDP協議實現,下面將分別講解。

TCP/IP協議

TCP/IP協議是面向連接的,即客戶端與服務器需要先建立連接后才能傳輸數據,以下是服務器端的代碼實現。

服務端:

import socketfrom threading import Threaddef deal(sock,addr): print(’Accept new connection from {}:{}’.format(addr[0],addr[1])) sock.send(’與服務器連接成功!’.encode(’utf-8’)) while True: data = sock.recv(1024).decode(’utf-8’) #1024為接收數據的最大大小 print(’receive from {}:{} :{}’.format(addr[0],addr[1],data)) sock.send(’信息已成功收到’.encode(’utf-8’))##創建tcp/IPV4協議的sockets = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#為socket綁定端口s.bind((’127.0.0.1’,10240))#監聽端口,參數5為等待的最大連接量s.listen(5)print('Waiting for connection...')while True: sock,addr = s.accept() t1 = Thread(target=deal,args=(sock,addr)) t1.start()#斷開與該客戶端的連接sock.close()s.close()

需要注意的是,服務器在等待客戶端連接時,即accept()函數這里是阻塞的,如下代碼每次只能接受一個客戶端的連接。

while True: #接受一個新連接,accept等待并返回一個客戶端連接 sock,addr = s.accept() print(’Accept new connection from {}:{}’.format(addr[0],addr[1])) #給客戶端發送消息 sock.send(’連接成功!’.encode(’utf-8’)) while True: data = sock.recv(1024).decode(’utf-8’) #1024為接收數據的最大大小 print(’receive from {}:{} :{}’.format(addr[0],addr[1],data)) sock.send(’信息已成功收到’.encode(’utf-8’)) #斷開與該客戶端的連接 sock.close()

也就是說如果采用以上方式,一個客戶端與服務器建立連接后,服務器就會進入一個死循環去收發該客戶端的信息,因此需要引入多線程,每與一個客戶端建立連接,就為其創建一個線程用于控制信息的收發,這樣便可以接受多個客戶端的連接了。

客戶端:

import sockets = socket.socket(socket.AF_INET,socket.SOCK_STREAM)##建立連接s.connect((’127.0.0.1’,10240))#接收客戶端連接成功服務器發來的消息print(s.recv(1024).decode(’utf-8’))while True: data = input(’發送給服務器:’) if len(data)>0:s.send(data.encode(’utf-8’)) print(’form sever:{}’.format(s.recv(1024).decode(’utf-8’)))s.close()

客戶端是比較簡單的,需要與服務器建立連接后,再進行收發信息,這里不再贅述了。

UDP協議

UDP協議是面向無連接的,即服務器與客戶端不需要提前建立連接,只需要向指定的端口直接發送數據即可。

服務端

import socket#為服務器創建socket并綁定端口 SOCK_DGRAM指定了socket的類型為udps = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)s.bind((’127.0.0.1’,7890))print(’Waiting for data...’)#upd無需監聽while True: data,addr = s.recvfrom(1024) print(’Recevie from {}:{} :{}’.format(addr[0],addr[1],data.decode(’utf-8’))) #sendto的另一個參數為客戶端socket地址 s.sendto(’信息已成功收到!’.encode(’utf-8’),addr)

客戶端

import socket#為服務器創建socket并綁定端口 SOCK_DGRAM指定了socket的類型為udps = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)while True: data = input(’發送給服務器:’) s.sendto(data.encode(’utf-8’),(’127.0.0.1’,7890)) print(’Receive from sever:{}’.format(s.recv(1024).decode(’utf-8’)))

可以看到UDP協議是非常簡單的,由于不需要建立連接,所以也不需要創建線程來管理數據的收發。

C/S模式的應用程序

python Socket網絡編程實現C/S模式和P2P

使用PyQt5對以上的程序進行封裝,這是基于TCP/IP協議實現的。

服務端

from PyQt5.QtWidgets import (QApplication,QPushButton, QWidget,QLineEdit,QTextEdit)import sysimport socketfrom threading import Threadimport datetimeclass UI(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self):#控件 self.clear_btn = QPushButton(’清空內容’,self) self.text = QTextEdit(self)#布局 self.clear_btn.setGeometry(150,400,100,40) self.text.setGeometry(20,20,360,370)self.text.setReadOnly(True)#信號連接 self.clear_btn.clicked.connect(self.commit) #初始化socket self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ##建立連接 self.s.bind((’127.0.0.1’,10240))self.s.listen(5) self.text.setText('Waiting for connection...') self.t = Thread(target = self.recv,args = ()) self.t.start() #主窗口布局 self.setGeometry(300, 300, 400, 450) self.setWindowTitle(’Server’) self.show() def commit(self): self.text.clear()def recv(self): while True: sock,addr = self.s.accept() t1 = Thread(target=self.deal,args=(sock,addr)) t1.start() sock.close()def deal(self,sock,addr): #sock,addr = s.accept() self.text.append(’Accept new connection from {}:{}’.format(addr[0],addr[1])) sock.send(’與服務器連接成功!’.encode(’utf-8’)) while True: data = sock.recv(1024).decode(’utf-8’) #1024為接收數據的最大大小 self.text.append(’[{}] receive from {}:{} :{}’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),addr[0],addr[1],data)) sock.send(’信息已成功收到’.encode(’utf-8’)) sock.close() def closeEvent(self,event): self.s.close() event.accept()if __name__ == ’__main__’: app = QApplication(sys.argv) ex = UI() sys.exit(app.exec_())

這里需要注意的是,由于Qt的主程序本身一直處于循環,如果直接阻塞等待客戶端連接會導致程序崩潰,因此需要在Qt初始化時創建一個線程用于等待客戶端的連接,要想同時多個客戶端訪問服務器,還需要在連接成功后再創建一個線程單獨用于接收該客戶端的數據。

客戶端

from PyQt5.QtWidgets import (QApplication,QPushButton, QWidget,QLineEdit,QTextEdit)import sysimport socketfrom threading import Threadimport datetimeclass UI(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self):#控件 self.edit = QLineEdit(self) self.commit_btn = QPushButton(’發送’,self) self.text = QTextEdit(self)#布局 self.edit.setGeometry(20, 410, 280, 30) self.commit_btn.setGeometry(310,410,70,30) self.text.setGeometry(20,20,360,380)self.text.setReadOnly(True)#信號連接 self.commit_btn.clicked.connect(self.commit) #初始化socket self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ##建立連接 self.s.connect((’127.0.0.1’,10240)) self.text.setText(’服務器 [{}]:{}n’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),self.s.recv(1024).decode(’utf-8’))) #主窗口布局 self.setGeometry(300, 300, 400, 450) self.setWindowTitle(’Client’) self.show() def commit(self): if len(self.edit.text()): text = self.edit.text() self.s.send(text.encode(’utf-8’)) self.text.append(’本機 [{}]:{}n’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)) self.text.append(’服務器 [{}]:{}n’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),self.s.recv(1024).decode(’utf-8’))) self.edit.clear()def closeEvent(self,event): self.s.close() event.accept() def recv(self): while True: passif __name__ == ’__main__’: app = QApplication(sys.argv) ex = UI() sys.exit(app.exec_())

客戶端還是比較簡單,不需要創建線程,在發送按紐點擊時觸發事件,向服務器發送數據,并將發送的數據與服務器返回的數據顯示在textEdit上。

P2P模式

python Socket網絡編程實現C/S模式和P2P

老師說P2P模式就是用兩個服務器相互連接通信(我以為是要客戶端發送給服務器,服務器再轉發給另一個客戶端),為了實現方便,直接采用UDP協議,也不用創建那么多線程了。代碼如下:

from PyQt5.QtWidgets import (QApplication,QPushButton, QWidget,QLineEdit,QTextEdit,QLabel)import sysimport socketfrom threading import Threadimport datetimeclass UI(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self):#控件 self.edit = QLineEdit(self) self.commit_btn = QPushButton(’發送’,self) self.text = QTextEdit(self) self.host_label = QLabel(’ip地址:’,self) self.host = QLineEdit(self) self.dst_port_label = QLabel(’目標端口:’,self) self.dst_port_edit = QLineEdit(self) self.src_port_label = QLabel(’本機端口:’,self) self.src_port_edit = QLineEdit(self) self.que_ren_btn = QPushButton(’確認’,self)#self.host_label.setStyleSheet('QLabel{font-size:25px}') #self.dst_port_label.setStyleSheet('QLabel{font-size:25px}') #self.src_port_label.setStyleSheet('QLabel{font-size:25px}') #布局 self.edit.setGeometry(20, 480, 280, 30) self.commit_btn.setGeometry(310,480,70,30) self.text.setGeometry(20,90,360,380) self.host_label.setGeometry(20,20,65,25) self.host.setGeometry(90,20,110,25) self.dst_port_label.setGeometry(205,20,65,25) self.dst_port_edit.setGeometry(275,20,110,25) self.src_port_label.setGeometry(20,55,65,25) self.src_port_edit.setGeometry(90,55,110,25) self.que_ren_btn.setGeometry(205,55,70,25)self.text.setReadOnly(True)#信號連接 self.commit_btn.clicked.connect(self.commit) self.que_ren_btn.clicked.connect(self.que_ren) #初始化socket self.s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #主窗口布局 self.setGeometry(300, 300, 400, 520) self.setWindowTitle(’Client’) self.show() def commit(self): if len(self.edit.text()): text = self.edit.text() self.s.sendto(text.encode(’utf-8’),(’127.0.0.1’,self.dst_port)) self.text.append(’本機 [{}]:n{}n’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)) self.edit.clear()def closeEvent(self,event): self.s.close() event.accept() def recv(self): while True: data,addr = self.s.recvfrom(1024) self.text.append(’{}:{}[{}]:n{}n’.format(addr[0],addr[1],datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),data.decode(’utf-8’))) def que_ren(self): self.src_port = int(self.src_port_edit.text()) self.dst_port = int(self.dst_port_edit.text()) #綁定ip地址與端口 self.s.bind((’127.0.0.1’,self.src_port)) #開啟接收消息的線程 self.t = Thread(target=self.recv,args=()) self.t.start()if __name__ == ’__main__’: app = QApplication(sys.argv) ex = UI() sys.exit(app.exec_())

首先需要輸入要傳送信息的IP地址,以及端口號,以及設置自己的端口號(IP地址沒有用到,我設置了是127.0.0.1),點擊確定按鈕時觸發事件,會為socket綁定端口號,并且創建一個用于接收消息的線程,在點擊發送按鈕時會觸發另一個事件用于發送消息,發送與接收的消息最后會顯示在TextEdit上。

注意

這里要統一說明一下,在使用Qt封裝后程序會一直循環運行,導致關閉程序時socket也沒有關閉(因為我也剛學,不清楚不關閉的后果,可能會占用這個端口一段時間吧),因此需要重寫Qt的closeEvent函數,在該函數中進行關閉。

總結

到此這篇關于python Socket網絡編程實現C/S模式和P2P的文章就介紹到這了,更多相關python Socket C/S模式和P2P內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Python 編程
相關文章:
主站蜘蛛池模板: 伊人久久免费 | 国产成人影院在线观看 | 欧美国产成人一区二区三区 | 又黄又刺激下面流水的视频 | 亚洲午夜在线观看 | 国产香蕉98碰碰久久人人 | avtom影院入口永久在线观看 | 亚洲福利视频一区二区三区 | 黄色国产网站 | 久久免费精品国产视频 | 99热.com| 免费久久精品 | 亚洲欧美日韩精品永久在线 | 天码毛片一区二区三区入口 | 香蕉亚洲精品一区二区 | 国产在线播放一区 | 欧美成人特黄级毛片 | 欧美顶级毛片在线播放 | 手机看片高清国产日韩片 | 国产不卡精品一区二区三区 | 国产成人久久精品二区三区牛 | 国产精品久久久久影视不卡 | a毛片在线 | 久久综合精品不卡一区二区 | 91免费观看视频 | 日本高清不卡中文字幕 | 久久精品成人一区二区三区 | 日本韩国一级片 | 久久一级视频 | 久久综合九九亚洲一区 | 国产在线手机视频 | 在线观看自拍视频 | 综合久久91| 福利岛国深夜在线 | 亚洲精品二区 | 亚洲第3页| 欧美日韩在线视频不卡一区二区三区 | 午夜在线亚洲 | 日本aaaaa毛片动漫 | 久久午夜影视 | 国产成人女人视频在线观看 |