国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - python Socket網絡編程實現C/S模式和P2P

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

2020-06-22 11:35阿君的貓 Python

這篇文章主要介紹了python Socket網絡編程實現C/S模式和P2P,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

C/S模式

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

TCP/IP協議

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

服務端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import socket
from threading import Thread
 
def 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協議的socket
s = 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()函數這里是阻塞的,如下代碼每次只能接受一個客戶端的連接。

?
1
2
3
4
5
6
7
8
9
10
11
12
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()

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

客戶端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import socket
 
s = 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協議是面向無連接的,即服務器與客戶端不需要提前建立連接,只需要向指定的端口直接發送數據即可。

服務端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import socket
 
#為服務器創建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無需監聽
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)

客戶端

?
1
2
3
4
5
6
7
8
9
import socket
 
#為服務器創建socket并綁定端口  SOCK_DGRAM指定了socket的類型為udp
s = 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協議實現的。

服務端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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('清空內容',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初始化時創建一個線程用于等待客戶端的連接,要想同時多個客戶端訪問服務器,還需要在連接成功后再創建一個線程單獨用于接收該客戶端的數據。

客戶端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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('發送',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:
      pass
 
if __name__ == '__main__':
  app = QApplication(sys.argv)
  ex = UI()
  sys.exit(app.exec_())

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

P2P模式

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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('發送',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內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/asfsfsdc/article/details/106872717

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 香蕉大人久久国产成人av | 天堂久久精品 | 日韩欧美在线视频 | 黄色三级网站 | 中文字幕精品一区 | 婷婷激情五月 | 黄色成人在线视频 | 日韩精品在线视频 | 成人在线免费观看 | 欧美在线观看免费观看视频 | 激情综合在线 | 亚洲精品久久久久久久久久久 | 日本三级视频在线观看 | 中文字幕一区二区三区四区五区 | 欧洲精品视频在线观看 | 黄色综合 | 欧美黄色片在线观看 | 久久久久综合精品福利啪啪 | 4438x成人网最大色成网站 | 国产精品激情在线观看 | 91色乱码一区二区三区 | 欧美大片免费观看 | 综合导航| 99re6在线视频精品免费 | 国产精品久久久久久一区二区三区 | 欧美中文字幕在线 | 亚洲精品视频免费 | 免费观看福利视频 | 人人99精 | 国产美女视频网站 | av毛片在线 | 久久影院免费观看 | 日本一区二区三区视频免费看 | 成人看片免费 | 香蕉福利视频 | 亚洲天堂一区 | 免费日韩成人 | 午夜激情视频在线观看 | a级在线免费观看 | 欧美在线| 久久aⅴ乱码一区二区三区 一区二区精品视频 |