網絡編程

網絡編程自我感受仍是很重要的一部分算法

網絡基礎

C/S架構 client/server
B/S架構 server/browser
 二者的關係?
 B/S架構是C/S架構的一種shell

計算機與計算機之間是如何通訊的?編程

兩臺計算機之間的通訊

網卡、網線服務器

網卡:提供網線的接口,經過網卡找到計算機,一個網卡擁有全球惟一的mac地址網絡

同一個局域網中多臺計算機之間的通訊

網卡,網線,交換機架構

交換機:一箇中心節點,全部的網線鏈接到交換機上併發

計算機1尋找計算機2併發消息的過程:socket

  計算機1發送消息到交換機,交換機把這個信息廣播給局域網中全部計算機,計算機2收到消息與本身的mac地址比對,確認是發給本身的消息以後,回覆消息給交換機,交換機發消息到計算機1ide

不一樣局域網中多臺計算機之間的通訊

網卡,網線,交換機,路由器函數

路由器:鏈接多個交換機

廣播:計算機1要和計算機2通訊,告訴交換機要找計算機2,交換機會告訴全部的計算機要找計算機2
廣播風暴:全部的計算機同時去找,同一臺計算機會接收到不少與本身不相關的信息,從而形成網絡擁堵
單播:只有計算機2會回覆消息給交換機,交換機發送給計算機1

網關:不一樣的局域網中的計算機之間通訊,同一個局域網的默認網關相同
子網掩碼:ip地址和子網掩碼按位與 (計算出來局域網的網段,同一個網段只有最後一位不一樣,前三位都相同)來判斷是否在同一局域網
按位與:1|1=1,1|0=1,0|0=0

ip地址

4個點分十進制(4個八位二進制數)範圍:0-255

做用:
經過ip地址能夠找到對應的mac地址 根據arp協議
127.0.0.1:本地迴環地址,本地中的兩個程序通訊

ip協議

IPV4:0.0.0.0-255.255.255.255
IPV6:0.0.0.0.0.0-255.255.255.255.255.255
做用:1.爲一臺計算機分配ip地址
   2.計算計算機的網段
若是想讓別人能訪問到本身的計算機中的程序,必須有一個已經在公網中註冊的ip地址

端口

計算機裏邊的每個須要聯網的程序都有一個端口

qq聊天時,對方不只須要你的ip地址,還須要qq程序的端口號
端口的範圍:0-25535
本身開端口:開8000後的端口

互聯網協議

每層的工做

  應用層   程序,要發送的數據包
  傳輸層   選擇通訊協議,給要發送的數據加上協議
  網絡層   給要發送的數據加上ip信息
  數據鏈路層    經過arp協議獲得mac地址,給要發送的數據加上mac地址
  物理層   兩個計算機連接
每層用到的協議:

  應用層   http協議,SMTP協議,ftp協議
  傳輸層   TCP/UDP協議
  網絡層   ip協議
  數據鏈路層   ARP協議
  物理層
每層常見物理設備:

  應用層
  傳輸層   四層交換機,四層路由器
  網絡層   路由器,三層交換機(帶路由功能)
  數據鏈路層    網橋,交換機,網卡
  物理層   中繼器,雙絞線,集線器

TCP協議/UDP協議

TCP協議:可靠的,創建連接的
  全雙工通訊:雙方能夠互相收發信息
  三次握手:必定是client先請求發送--server端接受請求而且請求發送--client端接收請求 通道鏈接成功
  四次揮手:client/server請求斷開鏈接--server/client贊成斷開--server/client請求斷開鏈接--client/server贊成斷開
UDP協議:
  不創建連接的,不可靠的

網絡編程

使用socket編程來進行進程間的通信

基於TCP協議的socket編程

TCP服務端:建立套接字 (socket)--綁定端口 (bind)--傾聽客戶請求(listen)--接受客戶端鏈接(accept)--接受、發送(recv、send)--關閉套接字(closesocket)
TCP客戶端:建立套接字(socket)--連接服務器(connect)--發送,接受(send、recv)--關閉套接字(closesocket)

import socket
soc = socket.socket()  #手機開機
soc.bind(('localhost',9999))    #啓動SIM卡
soc.listen()    #等待別人打電話
connect,addr = soc.accept()     #拿到通話鏈接,別人的電話號
recv = connect.recv(1024)       #聽別人講話
send = connect.send(b'hello')       #對別人講話
print(str(recv))
connect.close()     #掛斷電話
soc.close()     #關機
TCP_Server
import socket
sock = socket.socket()      #手機開機
sock.connect(('localhost',9999))       #給別人打電話
sock.send(b'jcc')       #對別人講話
rec = sock.recv(1024)       #聽別人講話
print(str(rec))
sock.close()    #關機
TCP_Client

基於UDP協議的socket編程

import socket
udpsk = socket.socket(type=socket.SOCK_DGRAM)   #建立一個服務器的套接字  DGRAM:datagram  基於udp傳輸的數據包
udpsk.bind(('localhost',8888))      #綁定指定服務器
while 1:
    msg,addr = udpsk.recvfrom(1024)     #接受消息
    print(msg.decode('utf-8'))
    if msg.decode('utf-8')=='bye':break
    inp = input('>>>')
    udpsk.sendto(bytes(inp,encoding='utf-8'),addr)  #發送消息
udpsk.close()  #關閉套接字
UDP_Server
import socket
udpsk = socket.socket(type=socket.SOCK_DGRAM)   #建立一個服務器的套接字  DGRAM:datagram  基於udp傳輸的數據包
udpsk.bind(('localhost',8888))      #綁定指定服務器
while 1:
    msg,addr = udpsk.recvfrom(1024)     #接受消息
    print(msg.decode('utf-8'))
    if msg.decode('utf-8')=='bye':break
    inp = input('>>>')
    udpsk.sendto(bytes(inp,encoding='utf-8'),addr)  #發送消息
udpsk.close()  #關閉套接字
UDP_Client

數據傳輸過程當中的黏包現象

現象:
    接受和發送不匹配
    
    基於UDP協議的傳輸不會出現黏包現象,一次接收不完的信息會被丟掉
    基於TCP協議的傳輸會出現黏包現象,可是不丟包
    基於UDP協議的傳輸會限制數據包的大小,超過的信息被丟掉
    基於TCP協議的傳輸不會限制數據包的大小
產生黏包的緣由:
    TCP協議是面向流的,無邊界的
    TCP協議有一種拆包機制,當發送的數據包大於網關的mtu(網絡上傳輸的最大數據包),該數據包就會被拆開,分批發送
 
     Nagle算法:優化傳輸速度(將屢次間隔較小且數據量小的數據合併成一個大的數據塊,封包)致使黏包現象
    
    黏包出現的最終緣由:不知道要接受的數據有多大

解決黏包方式1

先發送數據包的長度,根據長度接受數據(缺點:多了一次客戶服務器之間的交互)

import socket
sock = socket.socket()
sock.bind(('127.0.0.1',9991))
sock.listen()
conn,addr = sock.accept()
while 1:
    cmd = input('>>>')
    conn.send(cmd.encode('gbk'))

    len1 = conn.recv(1024)  #先接受長度

    recv = conn.recv(int(len1.decode('gbk')))   #根據長度接受數據包
    print('std:'+recv.decode('gbk'))
解決黏包Server
import socket
import subprocess
sock = socket.socket()
sock.connect(('127.0.0.1',9991))
while 1:
    cmd = sock.recv(1024)
    #執行計算機命令subprocess
    sb = subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    stdout = sb.stdout.read()
    stderr = sb.stderr.read()
    print('stdout'+str(len(stdout)))
    print('stderr' + str(len(stderr)))

    sock.send(str(len(stdout)+len(stderr)).encode('gbk'))   #發送長度

    sock.send(stdout)   #發送消息
    sock.send(stderr)
解決黏包Client

藉助struct模塊解決黏包

struct模塊

import struct
p = struct.pack('i',20)#int轉bytes
print(p)
num = b'1223'
unp = struct.unpack('i',num)[0]#bytes轉int
print(unp)
struct介紹

socketServer

import socketserver
class Myserver(socketserver.BaseRequestHandler):    #繼承BaseRequestHandler
    def handle(self):               #重寫handle函數
        self.data = self.request.recv(1024)     #self.request至關與conn,接受信息
        print(self.client_address[0])
        print(self.data.decode('utf-8'))
        self.request.sendall(self.data) #發送消息

if __name__ == '__main__':
    host,port = '127.0.0.1',9999
    socketserver.TCPServer.allow_reuse_address = True   # 設置allow_reuse_address容許服務器重用地址
    server = socketserver.TCPServer((host,port),Myserver)     # 建立一個server, 將服務地址綁定到127.0.0.1:9999
    server.serve_forever()  #程序一直運行
socketserver
相關文章
相關標籤/搜索