網絡編程


應用層: 它只負責產生相應格式的數據 ssh ftp nfs cifs dns http smtp pop3 
傳輸層: 定義數據傳輸的兩種模式:
TCP(傳輸控制協議:面向連接,可靠的,效率相對不高) 
UDP(用戶數據報協議:非面向連接,不可靠的,但效率高)
網絡層: 連接不同的網絡如以太網、令牌環網
IP (路由,分片) 、ICMP、 IGMP
ARP ( 地址解析協議,作用是將IP解析成MAC )
數據鏈路層: 以太網傳輸
物理層: 主要任務是規定各種傳輸介質和接口與傳輸信號相關的一些特性

tcp協議:三次握手四次揮手

socket(套接字):

tcp:

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898))  #把地址綁定到套接字
sk.listen()          #監聽鏈接
conn,addr = sk.accept() #接受客戶端鏈接
ret = conn.recv(1024)  #接收客戶端信息
print(ret)       #打印客戶端信息
conn.send(b'hi')        #向客戶端發送信息
conn.close()       #關閉客戶端套接字
sk.close()        #關閉服務器套接字(可選)
server端
import socket
sk = socket.socket()           # 創建客戶套接字
sk.connect(('127.0.0.1',8898))    # 嘗試連接服務器
sk.send(b'hello!')
ret = sk.recv(1024)         # 對話(發送/接收)
print(ret)
sk.close()            # 關閉客戶套接字
client端

udp

import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #創建一個服務器的套接字
udp_sk.bind(('127.0.0.1',9000))        #綁定服務器套接字
msg,addr = udp_sk.recvfrom(1024)
print(msg)
udp_sk.sendto(b'hi',addr)                 # 對話(接收與發送)
udp_sk.close()                         # 關閉服務器套接字
server端
import socket
ip_port=('127.0.0.1',9000)
udp_sk=socket.socket(type=socket.SOCK_DGRAM)
udp_sk.sendto(b'hello',ip_port)
back_msg,addr=udp_sk.recvfrom(1024)
print(back_msg.decode('utf-8'),addr)
client端

黏包問題:

黏包現象只發生在tcp協議中:

1.從表面上看,黏包問題主要是因為發送方和接收方的緩存機制、tcp協議面向流通信的特點。

2.實際上,主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所造成的

解決黏包問題

struct模塊

該模塊可以把一個類型,如數字,轉成固定長度的bytes

import socket
import struct
sk=socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
while True:
    info = input("<<<")
    if info =="q":
        break
    conn.send(info.encode('utf-8'))

    msg = conn.recv(4)
    ret=struct.unpack('i',msg)[0]
    ret=conn.recv(ret)
    print(ret.decode('gbk'))

conn.close()
sk.close()
server端
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
    cmd=sk.recv(1024)
    if cmd == 'q':
        break
    res = subprocess.Popen(cmd.decode('utf-8'), shell=True, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
                           stdout=subprocess.PIPE)
    stderr = res.stderr.read()
    stdout = res.stdout.read()
    ret=len(stderr)+len(stdout)
    ret=struct.pack('i',ret)
    sk.send(ret)
    sk.send(stderr)
    sk.send(stdout)
sk.close()
client端

上傳下載文件:

import socket
import os
import json
import struct
buffer=1024
sk=socket.socket()
sk.bind(('127.0.0.1',8880))#把地址綁定到套接字
sk.listen()#監聽鏈接
conn,addr = sk.accept() #接受客戶端鏈接
head_len = conn.recv(4)
head_len = struct.unpack('i',head_len)[0]
json_head = conn.recv(head_len).decode('utf-8')
head = json.loads(json_head)
file_size = head['file_size']
with open(head['file_name'],'wb')as f:
    while file_size:
        if file_size >= buffer:
            c=conn.recv(buffer)
            f.write(c)

            file_size -= buffer
        else:
            c=conn.recv(file_size)
            f.write(c)
            break

conn.close()
sk.close()
server端
import socket
import os
import json
import struct
sk = socket.socket()           # 創建客戶套接字
sk.connect(('127.0.0.1',8880))
buffer = 1024
head = {'file_size': None, 'file_path' : r'C:\Users\tom\Pictures\2016-10', 'file_name': 'IMG_0116.JPG'}
filepath = os.path.join(head['file_path'], head['file_name'])
file_size = os.path.getsize(filepath)
head['file_size'] = file_size
head_json = json.dumps(head)#字典轉字符串
head_bytes = head_json.encode('utf-8')#轉bytes

head_len = len(head_bytes)
pack_len = struct.pack('i',head_len)
sk.send(pack_len) #先發報頭的長度,4個bytes
sk.send(head_bytes) #再發報頭的字節格式
with open(filepath,'rb') as f:
    while file_size :
        if file_size > buffer:
            c=f.read(buffer)

            sk.send(c)
            file_size-=buffer
        else:
            c = f.read(file_size)
            sk.send(c)
            break


sk.close()
client端

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM