av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術(shù)文章
文章詳情頁

python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P

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

C/S模式

由于網(wǎng)絡(luò)課需要實(shí)現(xiàn)Socket網(wǎng)絡(luò)編程,所以簡單實(shí)現(xiàn)了一下,C/S模式分別用TCP/IP協(xié)議與UDP協(xié)議實(shí)現(xiàn),下面將分別講解。

TCP/IP協(xié)議

TCP/IP協(xié)議是面向連接的,即客戶端與服務(wù)器需要先建立連接后才能傳輸數(shù)據(jù),以下是服務(wù)器端的代碼實(shí)現(xiàn)。

服務(wù)端:

import socketfrom threading import Threaddef deal(sock,addr): print(’Accept new connection from {}:{}’.format(addr[0],addr[1])) sock.send(’與服務(wù)器連接成功!’.encode(’utf-8’)) while True: data = sock.recv(1024).decode(’utf-8’) #1024為接收數(shù)據(jù)的最大大小 print(’receive from {}:{} :{}’.format(addr[0],addr[1],data)) sock.send(’信息已成功收到’.encode(’utf-8’))##創(chuàng)建tcp/IPV4協(xié)議的sockets = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#為socket綁定端口s.bind((’127.0.0.1’,10240))#監(jiān)聽端口,參數(shù)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()

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

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

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

客戶端:

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

客戶端是比較簡單的,需要與服務(wù)器建立連接后,再進(jìn)行收發(fā)信息,這里不再贅述了。

UDP協(xié)議

UDP協(xié)議是面向無連接的,即服務(wù)器與客戶端不需要提前建立連接,只需要向指定的端口直接發(fā)送數(shù)據(jù)即可。

服務(wù)端

import socket#為服務(wù)器創(chuàng)建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無需監(jiān)聽while True: data,addr = s.recvfrom(1024) print(’Recevie from {}:{} :{}’.format(addr[0],addr[1],data.decode(’utf-8’))) #sendto的另一個參數(shù)為客戶端socket地址 s.sendto(’信息已成功收到!’.encode(’utf-8’),addr)

客戶端

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

可以看到UDP協(xié)議是非常簡單的,由于不需要建立連接,所以也不需要創(chuàng)建線程來管理數(shù)據(jù)的收發(fā)。

C/S模式的應(yīng)用程序

python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P

使用PyQt5對以上的程序進(jìn)行封裝,這是基于TCP/IP協(xié)議實(shí)現(xiàn)的。

服務(wù)端

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(’清空內(nèi)容’,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(’與服務(wù)器連接成功!’.encode(’utf-8’)) while True: data = sock.recv(1024).decode(’utf-8’) #1024為接收數(shù)據(jù)的最大大小 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的主程序本身一直處于循環(huán),如果直接阻塞等待客戶端連接會導(dǎo)致程序崩潰,因此需要在Qt初始化時創(chuàng)建一個線程用于等待客戶端的連接,要想同時多個客戶端訪問服務(wù)器,還需要在連接成功后再創(chuàng)建一個線程單獨(dú)用于接收該客戶端的數(shù)據(jù)。

客戶端

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(’發(fā)送’,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(’服務(wù)器 [{}]:{}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(’本機(jī) [{}]:{}n’.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),text)) self.text.append(’服務(wù)器 [{}]:{}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_())

客戶端還是比較簡單,不需要創(chuàng)建線程,在發(fā)送按紐點(diǎn)擊時觸發(fā)事件,向服務(wù)器發(fā)送數(shù)據(jù),并將發(fā)送的數(shù)據(jù)與服務(wù)器返回的數(shù)據(jù)顯示在textEdit上。

P2P模式

python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P

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

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(’發(fā)送’,self) self.text = QTextEdit(self) self.host_label = QLabel(’ip地址:’,self) self.host = QLineEdit(self) self.dst_port_label = QLabel(’目標(biāo)端口:’,self) self.dst_port_edit = QLineEdit(self) self.src_port_label = QLabel(’本機(jī)端口:’,self) self.src_port_edit = QLineEdit(self) self.que_ren_btn = QPushButton(’確認(rèn)’,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(’本機(jī) [{}]: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地址,以及端口號,以及設(shè)置自己的端口號(IP地址沒有用到,我設(shè)置了是127.0.0.1),點(diǎn)擊確定按鈕時觸發(fā)事件,會為socket綁定端口號,并且創(chuàng)建一個用于接收消息的線程,在點(diǎn)擊發(fā)送按鈕時會觸發(fā)另一個事件用于發(fā)送消息,發(fā)送與接收的消息最后會顯示在TextEdit上。

注意

這里要統(tǒng)一說明一下,在使用Qt封裝后程序會一直循環(huán)運(yùn)行,導(dǎo)致關(guān)閉程序時socket也沒有關(guān)閉(因為我也剛學(xué),不清楚不關(guān)閉的后果,可能會占用這個端口一段時間吧),因此需要重寫Qt的closeEvent函數(shù),在該函數(shù)中進(jìn)行關(guān)閉。

總結(jié)

到此這篇關(guān)于python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P的文章就介紹到這了,更多相關(guān)python Socket C/S模式和P2P內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Python 編程
相關(guān)文章:
主站蜘蛛池模板: 亚洲一区中文字幕 | 中文字幕乱码一区二区三区 | 免费毛片www com cn | 国产成人久久精品一区二区三区 | 国产亚洲网站 | 1000部精品久久久久久久久 | 国产精品二区三区在线观看 | 久久国产精品一区二区三区 | 免费啪啪| 日韩精品一二三区 | 中文字幕乱码一区二区三区 | 欧美精品一区二区三区在线 | 国产一区二区三区四区 | 精品免费国产一区二区三区四区 | 久久成人免费 | 欧美精品综合在线 | 91精品国产乱码久久久久久久久 | 日本一区二区在线视频 | 久久99网| 国产福利在线 | 日韩高清电影 | 亚洲国产精品久久久久婷婷老年 | 午夜欧美 | 欧美三区在线观看 | 日本成人在线免费视频 | 日韩字幕一区 | 久久1区| 视频在线一区二区 | www.youjizz.com日韩| 色小姐综合网 | 91pao对白在线播放 | 亚洲精品国产成人 | 中文字幕第二区 | 日韩欧美亚洲 | 91视频.com | 亚洲一区二区黄 | 国产黄色在线观看 | 韩国精品在线观看 | 亚洲国产精品va在线看黑人 | 日韩成人免费视频 | 亚洲一级黄色 |