MAC地址:是全球唯一標示的網(wǎng)絡接口,每一個網(wǎng)卡接口、交換機接口、路由器接口的mac地址均不相同。mac地址是通信子網(wǎng)內部相互通信的標識,交換機根據(jù)mac地址區(qū)分用戶。mac地址是物理層的概念。
IP地址:ip是網(wǎng)絡層的網(wǎng)絡協(xié)議,通過路徑檢測和邏輯尋址等方法使得兩個端系統(tǒng)(pc與服務器、手機與服務器、手機與PC等)可經(jīng)由通信子網(wǎng)中多個節(jié)點傳輸數(shù)據(jù)。ip是跨越2個端系統(tǒng)跨越多個通信子網(wǎng)相互通信的前提。常見協(xié)議有IPv4和IPv6。
端口:端口是應用層的概念,ip解決了不同的端系統(tǒng)之間相互通信的問題,但進行網(wǎng)絡通信的實際上是端系統(tǒng)內部的不同進程之間進行的,可能存在多個進程。為了區(qū)分端系統(tǒng)內部不同進程所以引入了端口的概念。有個比較形象的比方,ip地址好比大樓地址、端口好比房間號碼。一條進程可使用多端口,但一個端口只能被一條進程獨占使用,其他進程訪問被已被占用的端口會報端口沖突。
TCP協(xié)議:是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。建立連接需要三次握手,斷開連接需要四次揮手。優(yōu)點:有確認、窗口、重傳、擁塞控制機制,傳遞數(shù)據(jù)可以保證穩(wěn)定和可靠。缺點:效率低、占用系統(tǒng)資源高、易被攻擊 。常見的TCP應用及其端口有ssh:22、ftp:21、smtp:25、http:80、telnet:23、https:443、MYSQL:3306等。
UDP協(xié)議:是用戶數(shù)據(jù)報協(xié)議,提供面向事務的簡單不可靠信息傳送服務。使用UDP協(xié)議不用建立連接,它強調性能且不保證數(shù)據(jù)安全完整到達。優(yōu)點傳輸速度快,比TCP協(xié)議安全性略高。缺點:不可靠,不穩(wěn)定。常見的UDP應用及其端口有name server域名服務:53、bootps下載引導程序消息服務端:67、bootpc下載引導程序消息客戶端:68、TFTP簡單文件傳輸協(xié)議:69、RPC遠程過程調用:111、NTP網(wǎng)絡時間協(xié)議:123、SNMP簡單網(wǎng)絡管理協(xié)議:161、QQ:4000等。
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
說明:該方法有一個參數(shù),類型是元組(元組的第一個元素是IP,第二個元素是端口)。無返回值。
sk.listen()
說明:該方法有一個參數(shù),類型是int??梢灾付ㄖ付ㄏ到y(tǒng)允許暫未 accept 的連接數(shù),超過后將拒絕新連接。未指定則自動設為合理的默認值,一般使用缺省值即可。無返回值。
conn, ip_port = sk.accept()
說明:該方法無參數(shù)。返回2個值,第一個是socket實例,第二個是元組(元組的第一個元素是IP,第二個元素是端口)。如果server端需要服務多個客戶,那么accept()應該放入循環(huán),每次成功接入后開啟新的線程為新的客戶端服務。
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
說明:該方法有一個參數(shù),類型是元組(元組的第一個元素是IP,第二個元素是端口)。無返回值。
sk.sendall()
sk.recv()
import socketfrom threading import Threadfrom threading import enumerate as enimport timeHOST = '127.0.0.1' # IP地址PORT = 50007 # 端口max_connect = 5 # 最大連接數(shù)def talk(conn): while True: data = conn.recv(1024).decode() if data == 'q' or data == 'Q': return conn.sendall( f'服務端于{time.strftime('%Y年%m月%d日%H時%M分%S秒')}收到了你發(fā)來的“{data}”信息!'.encode())def main(): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() while True: conn, _ = s.accept() if len(en()) < max_connect: # 如果線程數(shù)未超過最大連接數(shù),那么開啟線程接入客戶端提供服務 Thread(target=talk, args=(conn,)).start()if __name__ == '__main__': main()
import socketimport sysHOST = '127.0.0.1' # IP地址PORT = 50007 # 端口with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) while True: message = input('輸入你想發(fā)給服務端的信息:') if not message: continue s.sendall(message.encode()) if message == 'q' or message == 'Q': break data = s.recv(1024).decode() print(f'收到服務端發(fā)來的信息:{data}')
def pack(n): if n >= 4294967296 or n < 0: raise ValueError('The value is out of range.') values = ((0b11111111000000000000000000000000, 24), (0b111111110000000000000000, 16), (0b1111111100000000, 8), (0b11111111, 0)) ret = b'' for i in values: x = (n & i[0]) >> i[1] x = x.to_bytes(length=1, byteorder='big') ret += x return retdef unpack(numlist): if len(numlist) != 4: raise ValueError('The bytes length must be 4.') values = (24, 16, 8, 0) ret = 0 i = 0 while i < 4: n = numlist[i] ret += n << values[i] i += 1 return ret
from os.path import getsize # 導入os模塊中getsize函數(shù),方便檢查文件大小class Transceiver: def __init__(self, conn, path='.', buffer=65536) -> None: self.conn = conn # 綁定接口 self.path = path # 綁定工作目錄 self.buffer = buffer # 綁定文件緩沖區(qū)大小 @staticmethod # 靜態(tài)方法 def pack(n: int) -> bytes: '''將int型長度值轉換成4字節(jié)bytes型數(shù)據(jù)''' if n >= 4294967296 or n < 0: raise ValueError('The value is out of range.') values = ((0b11111111000000000000000000000000, 24), (0b111111110000000000000000, 16), (0b1111111100000000, 8), (0b11111111, 0)) ret = b'' for i in values: x = (n & i[0]) >> i[1] x = x.to_bytes(length=1, byteorder='big') ret += x return ret @staticmethod # 靜態(tài)方法 def unpack(numlist: bytes) -> int: '''將4字節(jié)bytes型轉換回int型長度值''' if len(numlist) != 4: raise ValueError('The bytes length must be 4.') values = (24, 16, 8, 0) ret = 0 i = 0 while i < 4: n = numlist[i] ret += n << values[i] i += 1 return ret def send(self, message: str) -> None: '''發(fā)送字符串消息''' if (type(message) is str): # 判斷消息類型 message = message.encode() # 將消息轉成bytes型,缺省參數(shù)是utf8編碼 self.conn.sendall(self.pack(len(message))) # 發(fā)送消息前先發(fā)消息的長度 self.conn.sendall(message) # 發(fā)送消息 @property def recv(self) -> str: length = self.unpack(self.conn.recv(4)) return self.conn.recv(length).decode() # 返回消息字符串 def send_file(self, name: str) -> int: '''發(fā)送文件''' try: length = getsize(self.path + '/' + name) if length > 4294967295: # 文件大小超過4gb,返回 -2 ,停止發(fā)送文件 return -2 self.send(name + ',' + str(length)) with open(self.path + '/' + name, mode='rb') as f: # 二進制讀模式打開指定文件 while length >= 0: # 如果未發(fā)送的文件數(shù)據(jù)長度大于等于0則循環(huán) file = f.read(self.buffer) # 從文件中讀取指定大小的文件數(shù)據(jù) self.conn.sendall(file) # 發(fā)送文件數(shù)據(jù) length -= self.buffer # 計算未發(fā)送的文件數(shù)據(jù)長度 except FileNotFoundError: return -1 # 文件找不到,返回 -1 ,停止發(fā)送文件 return 1 # 文件正常發(fā)送完畢,返回1 def recv_file(self) -> int: '''接收文件''' try: name, length = self.recv.split(',') # 獲取文件名和文件長度 with open(self.path + '/' + name, mode='wb') as f: # 接收文件寫入指定目錄下 size = 0 # 計算接收的數(shù)據(jù)大小 length = int(length) # 文件長度 while length > size: # 文件長度大于已接收的數(shù)據(jù)長度則循環(huán) file = self.conn.recv(self.buffer) # 接收文件數(shù)據(jù) f.write(file) # 寫入文件數(shù)據(jù) size += len(file) # 累加已接收到的文件數(shù)據(jù)大小 except FileNotFoundError: return -1 # 文件找不到,返回 -1 ,停止發(fā)送文件 return 1 # 文件正常接收完畢,返回1
import socketfrom threading import Threadfrom threading import enumerate as enimport timeimport commonHOST = '127.0.0.1' # IP地址PORT = 50007 # 端口max_connect = 5def talk(conn): while True: m = common.Transceiver(conn, path='d:/2') data = m.recv if data == 'q' or data == 'Q': return elif data == 'file' or data == 'FILE': m.recv_file() else: m.send( f'服務端于{time.strftime('%Y年%m月%d日%H時%M分%S秒')}收到了你發(fā)來的“{data}”信息!')def main(): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() while True: conn, _ = s.accept() if len(en()) <= max_connect: Thread(target=talk, args=(conn,)).start()if __name__ == '__main__': main()
import socketimport commonHOST = '127.0.0.1' # IP地址PORT = 50007 # 端口with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) m = common.Transceiver(s, path='d:/1') while True: message = input('輸入你想發(fā)給服務端的信息:') if not message: continue m.send(message) if message == 'q' or message == 'Q': break elif message == 'file' or message == 'FILE': name = input('請輸入文件名:') check = m.send_file(name) if check == 1: print('文件發(fā)送成功!') elif check == -1: print('該文件找不到') elif check == -2: print('該文件超過4GB,太大了,不能發(fā)送!') continue data = m.recv print(f'收到服務端發(fā)來的信息:{data}')
聯(lián)系客服