Socket是網(wǎng)絡(luò)編程的一個(gè)抽象概念。通常我們用一個(gè)Socket表示“打開了一個(gè)網(wǎng)絡(luò)鏈接”,而打開一個(gè)Socket需要知道目標(biāo)計(jì)算機(jī)的IP地址和端口號,再指定協(xié)議類型即可。
TCP和UDP的區(qū)別:
- (TCP)傳輸控制協(xié)議,是一種提供可靠數(shù)據(jù)傳輸?shù)耐ㄓ脜f(xié)議。
- (UDP)用戶數(shù)據(jù)報(bào)協(xié)議,是一個(gè)面向無連接的協(xié)議。采用該協(xié)議不需要兩個(gè)應(yīng)用程序先建立連接。UDP協(xié)議不提供差錯恢復(fù),不能提供數(shù)據(jù)重傳,因此該協(xié)議傳輸數(shù)據(jù)安全性差。
以上是書面內(nèi)容
1、雙方都是一種[網(wǎng)絡(luò)傳輸協(xié)議]
2、TCP需要建立連接,而UDP不需要建立連接(無連接傳輸)
3、是否建立真實(shí)連接的特性,造成了雙方可靠性的差距。
- TCP屬于可靠的傳輸協(xié)議:因?yàn)閭鬏斍半p方建立好了連接,相當(dāng)于買賣雙方建立好了交易合同,傳輸中一般不會出現(xiàn)意外,直到連接終止;
- UDP屬于不可靠的傳輸協(xié)議:UDP的所謂連接相當(dāng)于一種映射,UDP單方面的認(rèn)為目標(biāo)地址(端口)是可用的,從而進(jìn)行收發(fā)數(shù)據(jù),而實(shí)際上目標(biāo)地址(端口)未必可用,所以傳輸數(shù)據(jù)不可靠
4、由于TCP需要建立真實(shí)的連接,所以需要消耗服務(wù)器的負(fù)載要大于UDP

TCP通信模型
tcp服務(wù)器
完成一個(gè)tcp服務(wù)器的功能,需要的流程如下:
- socket創(chuàng)建一個(gè)套接字
- bind綁定ip和port
- listen使套接字變?yōu)榭梢员粍渔溄?/li>
- accept等待客戶端的鏈接
- recv/send接收發(fā)送數(shù)據(jù)
客戶端
大多數(shù)連接都是可靠的TCP連接。創(chuàng)建TCP連接時(shí),主動發(fā)起連接的叫客戶端,被動響應(yīng)連接的叫服務(wù)器。
import socket
import time
# socket對象
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('1......')
'''
連接服務(wù)器,
如果連接上,繼續(xù)運(yùn)行
連接不上,報(bào)錯
'''
clientSocket.connect(('192.168.11.74',8888))
print('2......')
#關(guān)閉
clientSocket.close()
服務(wù)端
import socket
import time
# 買個(gè)手機(jī)
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 插卡
serverSocket.bind(('', 8888))
# 由飛行模式到接聽模式
serverSocket.listen(10)
print('1......')
'''
clientAddr:連接的客戶端的信息(ip,port)
'''
# 等待電話打入
newSocket, clientAddr = serverSocket.accept()
print('2......')
print(newSocket)
print(clientAddr)
# time.sleep(100)
# 關(guān)
newSocket.close() # 關(guān)閉之后,客戶端也會被關(guān)閉
serverSocket.close() # 項(xiàng)目運(yùn)行中服務(wù)器一直運(yùn)行,不會關(guān)閉
tcp服務(wù)端發(fā)送和接收消息
import socket
import time
'''
serverSocket是用來接收新的客戶端的
以后與這個(gè)連接的客戶端的收發(fā)消息就不能用serverSocket了,
而是用返回來的新的newSocket
'''
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
newSocket, clientAddr = serverSocket.accept()
#發(fā)
sendData = input('>>')
newSocket.send(sendData.encode('gbk'))
#收
'''
此時(shí)的recv會導(dǎo)致阻塞。
一旦對應(yīng)客戶端斷開了,不阻塞,并返回''的字符串
'''
recvData = newSocket.recv(1024)
print(recvData.decode('gbk'))
newSocket.close()
serverSocket.close()
客戶端接受和發(fā)送消息
import socket
import time
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect(('192.168.11.66',8888))
#發(fā)
sendData = input('>>')
clientSocket.send(sendData.encode('gbk'))
#收
recvData = clientSocket.recv(1024)
print(recvData.decode('gbk'))
clientSocket.close()
tcp服務(wù)器使用多線程接受多個(gè)客戶端
import socket
import time
import threading
def socketState(newSocket,clientAddr):
while True:
recvData = newSocket.recv(1024)
recvData = recvData.decode('gbk')
if recvData == '':
print('客戶端%s退出了...'%clientAddr[0])
newSocket.close()
break
else:
print('來自于%s:%s的消息(%s):%s'%(clientAddr[0],clientAddr[1],time.strftime('%Y-%m-%d %H:%M:%S'),recvData))
sendData = 'echo:%s'%recvData
newSocket.send(sendData.encode('gbk'))
def main():
#創(chuàng)建服務(wù)端socket對象
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
#循環(huán),等待多個(gè)客戶端連接
while True:
#等待客戶端的連接,阻塞。連接后,繼續(xù)運(yùn)行
newSocket, clientAddr = serverSocket.accept()
#創(chuàng)建新的線程,執(zhí)行與新客戶端的交互
serverThread = threading.Thread(target=socketState, args=(newSocket,clientAddr))
serverThread.start()
# 這里不能關(guān)閉,多線程共享數(shù)據(jù)
#newSocket.close()
if __name__ == '__main__':
main()
服務(wù)端使用多進(jìn)程接收多個(gè)客戶端
import socket
import time
import multiprocessing
def socketState(newSocket,clientAddr):
while True:
recvData = newSocket.recv(1024)
recvData = recvData.decode('gbk')
if recvData == '':
print('客戶端%s退出了...'%clientAddr[0])
newSocket.close()
break
else:
print('來自于%s:%s的消息(%s):%s'%(clientAddr[0],clientAddr[1],time.strftime('%Y-%m-%d %H:%M:%S'),recvData))
sendData = 'echo:%s'%recvData
newSocket.send(sendData.encode('gbk'))
def main():
#創(chuàng)建服務(wù)端socket對象
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind(('', 8888))
serverSocket.listen(10)
#循環(huán),等待多個(gè)客戶端連接
while True:
#等待客戶端的連接,阻塞。連接后,繼續(xù)運(yùn)行
newSocket, clientAddr = serverSocket.accept()
#創(chuàng)建新的進(jìn)程,執(zhí)行與新客戶端的交互
serverProcess = multiprocessing.Process(target=socketState, args=(newSocket,clientAddr))
serverProcess.start()
'''
這里要關(guān)閉。
子進(jìn)程會單獨(dú)分配與父進(jìn)程相同的內(nèi)容,地址不同(深拷貝)
'''
newSocket.close()
if __name__ == '__main__':
main()
總結(jié):
用TCP協(xié)議進(jìn)行Socket編程在Python中十分簡單,對于客戶端,要主動連接服務(wù)器的IP和指定端口,對于服務(wù)器,要首先監(jiān)聽指定端口,然后,對每一個(gè)新的連接,創(chuàng)建一個(gè)線程或進(jìn)程來處理。通常,服務(wù)器程序會無限運(yùn)行下去。
同一個(gè)端口,被一個(gè)Socket綁定了以后,就不能被別的Socket綁定了。