客戶端
- 創建一個基于TCP連接的Socket
AF_INET指定使用IPv4協議
AF_INET6指定使用IPv6協議
# 導入socket庫:
import socket# 創建一個socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連接:
s.connect(('www.sina.com.cn', 80))
- 客戶端要主動發起TCP連接
必須知道服務器的IP地址和端口號
連接新浪服務器
# 連接服務器
s.connect(('www.sina.com.cn', 80))
服務都有對應的標準端口號,
Web服務是80端口,
SMTP服務是25端口,
FTP服務是21端口,
端口號小于1024的是Internet標準服務的端口,
端口號大于1024的,可以任意使用。
- 建立TCP連接后,發送請求
# 發送數據:
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
- 接收數據
# 接收數據:
buffer = []
while True:# 每次最多接收1k字節:d = s.recv(1024)if d:buffer.append(d)else:break
data = b''.join(buffer)
接收數據時,調用recv(max)方法,一次最多接收指定的字節數,
因此,在一個while循環中反復接收,直到recv()返回空數據,表示接收完畢,退出循環。
接收到的數據包括HTTP頭和網頁本身,我們只需要把HTTP頭和網頁分離一下,
把HTTP頭打印出來,網頁內容保存到文件:
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# 把接收的數據寫入文件:
with open('sina.html', 'wb') as f:f.write(html)
在瀏覽器中打開這個sina.html文件,就可以看到新浪的首頁了。
5.關閉Socket,通信結束
# 關閉連接:
s.close()
服務器端
服務器進程首先要綁定一個端口并監聽來自其他客戶端的連接。
如果某個客戶端連接過來了,服務器就與該客戶端建立Socket連接,隨后的通信就靠這個Socket連接了。
一個Socket依賴4項:服務器地址、服務器端口、客戶端地址、客戶端端口來唯一確定一個Socket。
編寫一個簡單的服務器程序,它接收客戶端連接,把客戶端發過來的字符串加上Hello再發回去
- 創建一個基于IPv4和TCP協議的Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- 綁定監聽的地址和端口
用0.0.0.0綁定到所有的網絡地址,還可以用127.0.0.1綁定到本機地址。
127.0.0.1是一個特殊的IP地址,表示本機地址,如果綁定到這個地址,客戶端必須同時在本機運行才能連接
# 綁定端口:
s.bind(('127.0.0.1', 9999))
- 監聽端口
傳入的參數指定等待連接的最大數量
s.listen(5)
print('Waiting for connection...')
- 接受客戶端連接
服務器程序通過一個永久循環來接受來自客戶端的連接
while True:# 接受一個新連接:sock, addr = s.accept()# 創建新線程來處理TCP連接:t = threading.Thread(target=tcplink, args=(sock, addr))t.start()
- 多進程接受連接
每個連接都必須創建新線程(或進程)來處理,否則,單線程在處理連接的過程中,無法接受其他客戶端的連接
連接建立后,服務器首先發一條歡迎消息,然后等待客戶端數據,并加上Hello再發送給客戶端。如果客戶端發送了exit字符串,就直接關閉連接
def tcplink(sock, addr):print('Accept new connection from %s:%s...' % addr)sock.send(b'Welcome!')while True:data = sock.recv(1024)time.sleep(1)if not data or data.decode('utf-8') == 'exit':breaksock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))sock.close()print('Connection from %s:%s closed.' % addr)
-
退出服務器程序
服務器程序會永遠運行下去,必須按Ctrl+C退出程序。 -
測試所需的客戶端程序:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連接:
s.connect(('127.0.0.1', 9999))
# 接收歡迎消息:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:# 發送數據:s.send(data)print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()