最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2020年06月22日 09:52:33   作者:阿君的貓  
這篇文章主要介紹了python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

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 socket
from threading import Thread

def 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é)議的socket
s = 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 socket

s = 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的類型為udp
s = 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的類型為udp
s = 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)用程序


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

服務(wù)端

from PyQt5.QtWidgets import (QApplication,QPushButton,
             QWidget,QLineEdit,QTextEdit)
import sys
import socket
from threading import Thread

import datetime

class 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 sys
import socket
from threading import Thread

import datetime

class 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:
      pass

if __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模式


老師說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 sys
import socket
from threading import Thread

import datetime

class 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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python使用tkinter打造三維繪圖系統(tǒng)的示例代碼

    python使用tkinter打造三維繪圖系統(tǒng)的示例代碼

    Python?的?tkinter?模塊是一個常用的?GUI(圖形用戶界面)工具包,它能夠讓你創(chuàng)建窗口應(yīng)用程序,你可以使用它來構(gòu)建用戶友好的界面,包括按鈕、標(biāo)簽、文本框、列表框等各種控件,本文講給大家介紹如何使用tkinter打造三維繪圖系統(tǒng),需要的朋友可以參考下
    2023-08-08
  • 利用PyQT5日期控件制作一個小日歷

    利用PyQT5日期控件制作一個小日歷

    這篇文章主要介紹了利用PyQT5的日期控件制作一個小日歷,因為pyqt5已經(jīng)自帶了相關(guān)的日期控件,只需要明白如何調(diào)用再加上比較個性化的功能,這個日歷的小控件就制作完成了。需要的可以參考一下
    2022-01-01
  • Python圖像處理庫PIL詳細(xì)使用說明

    Python圖像處理庫PIL詳細(xì)使用說明

    Pillow是Python中較為基礎(chǔ)的圖像處理庫,主要用于圖像的基本處理,比如裁剪圖像、調(diào)整圖像大小和圖像顏色處理等,需要的朋友可以參考下
    2022-04-04
  • django 解決model中類寫不到數(shù)據(jù)庫中,數(shù)據(jù)庫無此字段的問題

    django 解決model中類寫不到數(shù)據(jù)庫中,數(shù)據(jù)庫無此字段的問題

    這篇文章主要介紹了django 解決model中類寫不到數(shù)據(jù)庫中,數(shù)據(jù)庫無此字段的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨想過來看看吧
    2020-05-05
  • python通過getopt模塊如何獲取執(zhí)行的命令參數(shù)詳解

    python通過getopt模塊如何獲取執(zhí)行的命令參數(shù)詳解

    這篇文章主要給大家介紹了關(guān)于python通過getopt模塊如何獲取執(zhí)行的命令參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • linux之文件查找指定文件中包含關(guān)鍵字的行信息方式

    linux之文件查找指定文件中包含關(guān)鍵字的行信息方式

    這篇文章主要介紹了linux之文件查找指定文件中包含關(guān)鍵字的行信息方式,具有很好的參考價值,希望對大家有所幫助。
    2023-06-06
  • python?包實(shí)現(xiàn)JSON?輕量數(shù)據(jù)操作

    python?包實(shí)現(xiàn)JSON?輕量數(shù)據(jù)操作

    這篇文章主要介紹了python?包實(shí)現(xiàn)JSON?輕量數(shù)據(jù)操作,文章介紹內(nèi)容首先將對象轉(zhuǎn)為json字符串展開主題詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • 詳解Pytorch顯存動態(tài)分配規(guī)律探索

    詳解Pytorch顯存動態(tài)分配規(guī)律探索

    這篇文章主要介紹了Pytorch顯存動態(tài)分配規(guī)律探索,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 深入挖掘Python自定義加密算法的設(shè)計與實(shí)現(xiàn)

    深入挖掘Python自定義加密算法的設(shè)計與實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Python中自定義加密算法的設(shè)計與實(shí)現(xiàn)的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-12-12
  • Pytest 自動化測試框架的使用

    Pytest 自動化測試框架的使用

    本文主要介紹了Pytest 自動化測試框架的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03

最新評論

东明县| 顺昌县| 大厂| 周口市| 金沙县| 韶关市| 肇州县| 安宁市| 成都市| 油尖旺区| 神木县| 井研县| 大兴区| 政和县| 绥德县| 宁夏| 色达县| 保德县| 山东省| 布拖县| 巧家县| 罗甸县| 杨浦区| 南召县| 舟曲县| 洞头县| 甘南县| 松江区| 肥城市| 宁德市| 浦东新区| 青阳县| 七台河市| 旌德县| 双鸭山市| 拜泉县| 河津市| 互助| 禄丰县| 惠东县| 武城县|