[TOC]
## **一 最簡單的C/S實現**
基于前面的打電話偽代碼,實現服務器與客戶端的單次通信
**server端代碼**
```
import socket
#1、買手機
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#2、綁定手機卡
phone.bind(('127.0.0.1',8081)) #元組形式的主機和端口
#3、開機
phone.listen(5) #允許5個連接排隊
#4、等電話鏈接
print('starting...')
conn,client_addr=phone.accept() #接受的數據是一個元組
#5、收,發消息
data=conn.recv(1024) #1024代表最大接收1024個bytes
print('客戶端的數據',data.decode('utf-8')) #接受的是bytes,需要轉碼
conn.send(data.upper())
#6、掛電話
conn.close()
#7、關機
phone.close()
```
**client端代碼**
```
import socket
#1、買手機
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#2、撥號
phone.connect(('127.0.0.1',8081))
#3、發,收消息
phone.send('hello'.encode('utf-8')) #只能發送bytes類型,所以要轉碼
data=phone.recv(1024)
print(data.decode('utf-8'))
#4、關閉
phone.close()
```
## **二 循環發送消息的實現**
上面的代碼客戶端和服務器斷只能通信一次,然后就會斷開連接,如果想多次發送數據,就需要加入循環語句
**server端代碼**
```
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8083))
phone.listen(5)
print('starting...')
conn,client_addr=phone.accept()
while True: #通信循環
data=conn.recv(1024)
print('客戶端的數據',data)
conn.send(data.upper())
conn.close()
phone.close()
```
**client端代碼**
```
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8083))
while True: #通信循環
msg=input('>>: ').strip()
if not data:continue #避免發送空數據
phone.send(msg.encode('utf-8'))
data=phone.recv(1024)
print(data)
phone.close()
```
### **bug解釋和修復**
上面的代碼有2個bug,關于bug的說明和修改方式如下
1. client直接斷開服務的話,server端會報錯
修改server端的通信循環為如下樣式,分別針對linux和windows服務器做不同的處理
```
while True: #通信循環
try:
data=conn.recv(1024)
if not data:break #適用于linux操作系統
print('客戶端的數據',data)
conn.send(data.upper())
except ConnectionResetError: #適用于windows操作系統
break
```
2. 重啟server端時可能提示端口占用
問題是由于服務端仍然存在四次揮手的time_wait狀態在占用地址
解決方法1:socket方法
~~~
sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #寫在bind前
sock_server.bind((HOST, PORT))
~~~
解決方法2:linux內核辦法
`vi /etc/sysctl.conf`,在打開文件中加入以下內容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后執行 `/sbin/sysctl -p `讓參數生效。
>net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關閉;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
## **循環建立連接的實現**
上面的C/S結構代碼,僅能支持client與server一對一的通信,如果client斷開連接也不會有新的客戶端被接入,因此需要server段再建立連接處再加一層循環實現循環建立連接
**server端代碼**
```
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8083)) #0-65535:0-1024給操作系統使用
phone.listen(5)
print('starting...')
while True: # 鏈接循環
conn,client_addr=phone.accept()
print(client_addr)
while True: #通信循環
try:
data=conn.recv(1024)
if not data:break #適用于linux操作系統
print('客戶端的數據',data)
conn.send(data.upper())
except ConnectionResetError: #適用于windows操作系統
break
conn.close()
phone.close()
```
client端代碼不需要任何改變
### **特別說明**
如上修改后,能實現多個客戶端排隊連接客戶端進行通話的情況,但是實現不了多個客戶端同時連接服務端通話的情況,需要用到后面的**并發編程**知識
- 基礎部分
- 基礎知識
- 變量
- 數據類型
- 數字與布爾詳解
- 列表詳解list
- 字符串詳解str
- 元組詳解tup
- 字典詳解dict
- 集合詳解set
- 運算符
- 流程控制與循環
- 字符編碼
- 編的小程序
- 三級菜單
- 斐波那契數列
- 漢諾塔
- 文件操作
- 函數相關
- 函數基礎知識
- 函數進階知識
- lambda與map-filter-reduce
- 裝飾器知識
- 生成器和迭代器
- 琢磨的小技巧
- 通過operator函數將字符串轉換回運算符
- 目錄規范
- 異常處理
- 常用模塊
- 模塊和包相關概念
- 絕對導入&相對導入
- pip使用第三方源
- time&datetime模塊
- random隨機數模塊
- os 系統交互模塊
- sys系統模塊
- shutil復制&打包模塊
- json&pickle&shelve模塊
- xml序列化模塊
- configparser配置模塊
- hashlib哈希模塊
- subprocess命令模塊
- 日志logging模塊基礎
- 日志logging模塊進階
- 日志重復輸出問題
- re正則表達式模塊
- struct字節處理模塊
- abc抽象類與多態模塊
- requests與urllib網絡訪問模塊
- 參數控制模塊1-optparse-過時
- 參數控制模塊2-argparse
- pymysql數據庫模塊
- requests網絡請求模塊
- 面向對象
- 面向對象相關概念
- 類與對象基礎操作
- 繼承-派生和組合
- 抽象類與接口
- 多態與鴨子類型
- 封裝-隱藏與擴展性
- 綁定方法與非綁定方法
- 反射-字符串映射屬性
- 類相關內置方法
- 元類自定義及單例模式
- 面向對象的軟件開發
- 網絡-并發編程
- 網絡編程SOCKET
- socket簡介和入門
- socket代碼實例
- 粘包及粘包解決辦法
- 基于UDP協議的socket
- 文件傳輸程序實戰
- socketserver并發模塊
- 多進程multiprocessing模塊
- 進程理論知識
- 多進程與守護進程
- 鎖-信號量-事件
- 隊列與生產消費模型
- 進程池Pool
- 多線程threading模塊
- 進程理論和GIL鎖
- 死鎖與遞歸鎖
- 多線程與守護線程
- 定時器-條件-隊列
- 線程池與進程池(新方法)
- 協程與IO模型
- 協程理論知識
- gevent與greenlet模塊
- 5種網絡IO模型
- 非阻塞與多路復用IO實現
- 帶著目標學python
- Pycharm基本使用
- 爬蟲
- 案例-爬mzitu美女
- 案例-爬小說
- beautifulsoup解析模塊
- etree中的xpath解析模塊
- 反爬對抗-普通驗證碼
- 反爬對抗-session登錄
- 反爬對抗-代理池
- 爬蟲技巧-線程池
- 爬蟲對抗-圖片懶加載
- selenium瀏覽器模擬