計算機基礎(chǔ)
應(yīng)用 -> 控制程序(操作系統(tǒng)) -> 計算機硬件
c/s架構(gòu)舟舒, 通過網(wǎng)絡(luò)進行通訊。
什么是網(wǎng)絡(luò)?
OSI七層協(xié)議
應(yīng)用層 表示層 會話層 傳輸層 傳輸層 網(wǎng)絡(luò)層 數(shù)據(jù)鏈路層 物理層
五層協(xié)議
- 物理層 電信號
- 數(shù)據(jù)鏈路層
- 以太網(wǎng)協(xié)議(Ethernet)
- 數(shù)據(jù)報或數(shù)據(jù)幀head+data
- head18個字節(jié)(6源地址 6目的地址 6描述data類型)
- 基于mac地址廣播方式, 同一子網(wǎng)內(nèi)通訊
- 網(wǎng)絡(luò)層
- ip協(xié)議
- ip頭+data
- arp協(xié)議: 將ip地址轉(zhuǎn)換為mac地址
- 傳輸層
- tcp/udp
- 應(yīng)用層
- http现斋, ftp
1. 什么是c/s架構(gòu)?
c/s又稱Client/Server服務(wù)模式解取。這種結(jié)構(gòu)的系統(tǒng)把較為復(fù)雜的計算和管理任務(wù)交給網(wǎng)絡(luò)上的高檔機器步责,而把頻繁與客戶打交道的任務(wù)交給客戶機。任何一個應(yīng)用系統(tǒng),不管是簡單的單機系統(tǒng)還是復(fù)雜的網(wǎng)絡(luò)系統(tǒng)蔓肯,都由3個部分組成:顯示邏輯部分(表示層)遂鹊、事務(wù)處理邏輯部分(功能層)和數(shù)據(jù)處理邏輯部分(數(shù)據(jù)層)。顯示邏輯部分的功能是與用戶進行交互蔗包;事務(wù)處理邏輯部分的功能是進行具體的運算和數(shù)據(jù)的處理秉扑;數(shù)據(jù)處理邏輯部分的功能是對數(shù)據(jù)庫中的數(shù)據(jù)進行查詢、修改和更新等调限。在兩層模式的Client/Server結(jié)構(gòu)中舟陆,顯示邏輯部分和事務(wù)處理邏輯部分均被放在客戶端,數(shù)據(jù)處理邏輯部分和數(shù)據(jù)庫被放在服務(wù)器端耻矮。這樣就使得客戶端變得很“胖”秦躯,成為胖客戶機,而服務(wù)器端的任務(wù)相對較輕裆装,成為瘦服務(wù)器踱承。
2. 互聯(lián)網(wǎng)協(xié)議是什么?分別介紹五層協(xié)議中每一層的功能哨免?
互聯(lián)網(wǎng)協(xié)議是網(wǎng)絡(luò)通信中統(tǒng)一的標(biāo)準(zhǔn)茎活。
五層協(xié)議
物理層 主要功能是基于電器特性發(fā)送高低電壓(電信號),高電壓對應(yīng)數(shù)字1琢唾,低電壓對應(yīng)數(shù)字0载荔;
-
數(shù)據(jù)鏈路層 主要功能定義了電信號的分組方式。關(guān)鍵字:ethernet,mac, 廣播
-
網(wǎng)絡(luò)層 功能是引入一套新的地址來區(qū)分不同的廣播域采桃、子網(wǎng)懒熙,這套地址即網(wǎng)絡(luò)地址。關(guān)鍵字:ip協(xié)議芍碧、子網(wǎng)掩碼煌珊、ip地址分類号俐、ip報文泌豆、arp協(xié)議、ICMP吏饿、ping踪危、tracetroute
-
傳輸層 功能是建立端口到端口的通信,端口范圍是0-65535猪落, 0-1023為系統(tǒng)占用端口贞远。傳輸層有兩層層協(xié)議:TCP/UDP
-
tcp協(xié)議 可靠傳輸,TCP數(shù)據(jù)包沒有長度限制笨忌,理論上可以無限長蓝仲,但是為了保證網(wǎng)絡(luò)的效率,通常TCP數(shù)據(jù)包的長度不會超過IP數(shù)據(jù)包的長度,以確保單個TCP數(shù)據(jù)包不必再分割袱结。
- udp協(xié)議亮隙, 不可靠傳輸,”報頭”部分一共只有8個字節(jié)垢夹,總長度不超過65,535字節(jié)溢吻,正好放進一個IP數(shù)據(jù)包。
-
應(yīng)用層
3.基于tcp協(xié)議通信果元,為何建立鏈接需要三次握手促王,而斷開鏈接卻需要四次揮手?
三次握手:
- 客戶端發(fā)送syn包(syn=x)到服務(wù)器而晒,并進入SYN_SEND狀態(tài)蝇狼,等待服務(wù)器確認。
- 服務(wù)器收到syn包倡怎,必須確認客戶的SYN(ack=x+1)题翰,同時自己也發(fā)送一個SYN包(syn=y),即SYN+ACK包诈胜,此時服務(wù)器進入SYN_RECV狀態(tài)豹障。
- 客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認包ACK(ACK=y+1)焦匈,此包發(fā)送完畢血公,服務(wù)端和客戶端進入ESTABLISHED狀態(tài),完成三次握手缓熟。
四次揮手
- 主動關(guān)閉方發(fā)送一個FIN累魔,來關(guān)閉到被動關(guān)閉方的數(shù)據(jù)發(fā)送。
- 被動關(guān)閉方收到FIN包后够滑,發(fā)送一個ACK給對方垦写,確認序號為收到序號+1
- 被動關(guān)閉方發(fā)送一個FIN,用來關(guān)閉被動關(guān)閉方到主動關(guān)閉方的數(shù)據(jù)傳送彰触,就是告訴主動關(guān)閉方梯投,我的數(shù)據(jù)也發(fā)完了
- 主動關(guān)閉方收到FIN后,發(fā)送一個ACK給被動關(guān)閉方况毅,確認序列號為收到序號+1
4.為何基于tcp協(xié)議的通信比基于udp協(xié)議的通信更可靠分蓖?
tcp:可靠 對方給了確認收到信息,才發(fā)下一個尔许,如果沒收到確認信息就重發(fā)
udp:不可靠 一直發(fā)數(shù)據(jù)么鹤,不需要對方回應(yīng)
5.流式協(xié)議指的是什么協(xié)議,數(shù)據(jù)報協(xié)議指的是什么協(xié)議味廊?
流式協(xié)議:TCP協(xié)議蒸甜,可靠傳輸
數(shù)據(jù)報協(xié)議: UDP協(xié)議棠耕,不可傳輸
6.什么是socket?簡述基于tcp協(xié)議的套接字通信流程
socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層柠新,他是一組接口昧辽。
7.什么是粘包? socket 中造成粘包的原因是什么登颓? 哪些情況會發(fā)生粘包現(xiàn)象搅荞?
粘包:數(shù)據(jù)粘在一起,主要因為:接收方不知道消息之間的界限框咙,不知道一次性提取多少字節(jié)的數(shù)據(jù)造成的
數(shù)據(jù)量比較小咕痛,時間間隔比較短,就合并成了一個包
8.基于socket開發(fā)一個聊天程序喇嘱,實現(xiàn)兩端互相發(fā)送和接收消息
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:27
# @File : sever.py
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 8080))
server.listen(5)
print('Starting...')
while True:
conn, addr = server.accept()
while True:
data = conn.recv(1024)
if not data:
break
print("%s: %s" % (addr[0], data.decode('utf-8')))
msg = input(">>>:").strip()
if not msg:
continue
conn.send(msg.encode('utf-8'))
conn.close()
server.close()
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:28
# @File : client.py
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
msg = input(">>>: ").strip()
if not msg:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
9.基于tcp socket茉贡,開發(fā)簡單的遠程命令執(zhí)行程序,允許用戶執(zhí)行命令者铜,并返回結(jié)果
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:27
# @File : sever.py
import socket
import subprocess
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 8080))
server.listen(5)
print('Staring...')
while True:
conn, addr = server.accept()
while True:
data = conn.recv(1024)
if not data:
break
obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr= subprocess.PIPE)
conn.send(obj.stdout.read())
conn.send(obj.stderr.read())
conn.close()
server.close()
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:28
# @File : client.py
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
msg = input(">>>: ").strip()
if not msg:
continue
client.send(msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
10. 基于tcp協(xié)議編寫簡單FTP程序腔丧,實現(xiàn)上傳、下載文件功能作烟,并解決粘包問題
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:27
# @File : sever.py
import struct
import json
import socket
from os import path
file_dir = path.join(path.dirname(__file__), 'data')
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 8080))
server.listen(5)
print('Staring...')
def pack_header(data, filename):
header = {
'file_name': path.split(filename)[1],
'data_size': len(data),
'exists': path.isfile(filename),
}
json_header = json.dumps(header).encode('utf-8')
header_len = struct.pack('i', len(json_header))
return header_len, json_header
while True:
conn, addr = server.accept()
while True:
cmd = conn.recv(1024)
if not cmd:
break
command = cmd.decode('utf-8').split()
if command[0] == 'get':
file = command[1]
filename = path.join(file_dir, file)
if path.isfile(filename):
with open(filename, 'rb') as f:
data= f.read()
else:
data = '%s not exists...' % file
data = data.encode('utf-8')
p_header = pack_header(data, filename)
conn.send(p_header[0])
conn.send(p_header[1])
conn.send(data)
elif command[0] == 'put':
print(123)
header_len = struct.unpack('i', conn.recv(4))[0]
print(header_len)
json_header = conn.recv(header_len)
print(json_header)
header = json.loads(json_header.decode('utf-8'))
file = path.split(header['file_name'])[1]
data_size = header['data_size']
size = 0
filename = path.join(file_dir, file)
with open(filename, 'wb') as f:
while size < data_size:
data = conn.recv(1024)
f.write(data)
size += len(data)
conn.close()
server.close()
#!/usr/bin/env python3
# Author : fbo
# @Time : 18-5-7 下午8:28
# @File : client.py
import struct
import json
import socket
from os import path
file_dir = path.join(path.dirname(__file__), 'data')
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
def pack_header(data, filename):
header = {
'file_name': path.split(filename)[1],
'data_size': len(data),
'exists': path.isfile(filename),
}
json_header = json.dumps(header).encode('utf-8')
header_len = struct.pack('i', len(json_header))
return header_len, json_header
while True:
msg = input(">>>: ").strip()
if not msg:
continue
if msg.startswith('get'):
client.send(msg.encode('utf-8'))
header_len = struct.unpack('i', client.recv(4))[0]
json_header = client.recv(header_len)
header = json.loads(json_header.decode('utf-8'))
file = path.split(header['file_name'])[1]
data_size = header['data_size']
size = 0
filename = path.join(file_dir, file)
if header['exists']:
with open(filename, 'wb') as f:
while size < data_size:
data = client.recv(1024)
f.write(data)
size += len(data)
else:
data = client.recv(1024).decode('utf-8')
print(data)
elif msg.startswith('put'):
client.send(msg.encode('utf-8'))
command = msg.split()
file = command[1]
filename = path.join(file_dir, file)
if path.isfile(filename):
with open(filename, 'rb') as f:
data = f.read()
p_header = pack_header(data, filename)
client.send(p_header[0])
client.send(p_header[1])
client.send(data)
else:
print('%s not exists...' % file)
client.close()
11. 基于udp協(xié)議編寫程序愉粤,實現(xiàn)功能
- 執(zhí)行指定的命令,讓客戶端可以查看服務(wù)端的時間
- 執(zhí)行指定的命令拿撩,讓客戶端可以與服務(wù)的的時間同步
# sever.py
# _*_ coding: utf-8 _*_
import socket
import subprocess
import time
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))
while True:
data, client_addr = server.recvfrom(1024)
print(data, client_addr)
obj = subprocess.Popen(data.decode('utf-8'),shell=True, # time 命令在windows 下不能用
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
print(stdout+stderr)
server.sendto(stdout+stderr,client_addr)
if data.decode('utf-8') == 'time':
str_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
# str_time = '2017-01-01 00:00:00'
server.sendto(str_time.encode('gbk'), client_addr)
server.close()
# client.py
# _*_ coding: utf-8 _*_
import socket
import os
import time
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg = input('>>>:').strip()
client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
data,server_addr = client.recvfrom(1024)
print(data.decode('utf-8'),server_addr)
localtime = time.localtime()
os.system("date %d-%d-%d" % (localtime.tm_year, localtime.tm_mon, localtime.tm_mday)) # 設(shè)置日期
os.system("time %d:%d:%d.0" % (localtime.tm_hour, localtime.tm_min, localtime.tm_sec)) # 設(shè)置時間
client.close()