一,TCP通信模型
TCP服务端:
1.调用socket():建立socket套接字,此建立的socket是主动套接字。默认是用于主动发送请求的sokcet。后面需要变为被动套接字,即用于接收数据。
2.调用bind()函数:邦定服务端和其他一样,若想要接收到数据,必须邦定一个ip和port。这样客户端才能准确发送到这个服务器来。就好像你只有告诉对方你的手机号码,别人才能准确打通你手机。
3.调用listen():listen是将socket转变为被动套接字。这样服务器才可以接收到客户端的请求。就好像你有一个手机,你已经告诉对方你的手机号码了,接下来你就要将你的手机来电设置为响铃模式,别人发送数据过来,你才能知道吧。这也是为什么要加listen(听)的原因了。如果不调用listen,那么就相当于你手机来电为静音,别人发送消息过来,你肯定不知道了。所以没有调用listen的socket是主动的,你只能给别人打电话,别人打电话给你你却不知道。
4.调用accept():accept是开始等待对方连接进来,就好像你开始等待别人打电话进来。如果对方没有连进来。accept会处于阻塞状态,即一直等待对方连接进来。如果来了一个连接,accpet会返回一个元组=(用于处理客户端信息的套接字,客户端的ip和端口号)。
5.用于处理客户端数据的套接字(即用于发送数据 和接收数据 )开始与客户端交互。这里有个疑问,为什么不用一开始创建的socket来处理呢。这是为了更好的处理多用户模式,一开始创建的serverSocket一心一意用于监听是否有客户端连接进来,如果有,交给一个clientSocket套接字一处理与客户端的交互。而serverSocket则去监听别的客户端是否连接进来。举个栗子,你给10086服务器打电话,一开始是系统的接听,而当你要使用人工服务的时候,系统会自动分配一个人专门与你进行交互。而系统则去一心一意监听别的人是否拨打10086。
总结:
TCP客户端:
1.调用socket():客户端就比较简单,首先建立socket。
2.调用connect():connect连接要进行交互的服务器,连接的时候加上参数(对方的ip和port)
3.send和recv与服务器进行交互。
二,TCP编程之进行简单的通信
TCP服务端(只能处理一个请求):
import socket
#建立tcp协议的socket,这个socket是主动套接字,这个serverSocket只用于监听接收其他客户端
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind(('',8899))
#将主动套接字变为被动套接字,这样才样让其监听到其他客户端
serverSocket.listen(5)
print('正在等待别的客户端连进来')
#开始监听,如果没有客户端连进来,会处于阻塞状态。conn是用于服务客户端的套接字
conn,addr = serverSocket.accept()
print(conn,addr)
##<socket.socket fd=384, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8899), raddr=('127.0.0.1', 60926)> ('127.0.0.1', 60926)
data = conn.recv(1024)
print(data)
conn.close()
serverSocket.close()
TCP客户端:
import socket
client = socket.socket()
client.connect(('192.168.1.105',8899))
client.send(b'hkj')
client.close()
三,TCP编程之同时处理多个用户
server端:
import socket
import threading
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind(('',8899))
serverSocket.listen(5)
def handle_request(conn):
while True:
try:#linux系统中,若客户端关闭套接字,则recv会为空,在windos中,会报异常,所以要进行抓住异常
recvData = conn.recv(1024)
print('recv:',recvData.decode())
conn.send(recvData)
except Exception as f:
print('a client is lost...')
break
while True:
#没有链接将会处理阻塞
conn,addr = serverSocket.accept()
print('a client connect in..,addr:',addr)
#用于同时处理多个请求,这样多个客户端就可以同时都连接进来
t = threading.Thread(target=handle_request,args=(conn,))
t.start()
serverSocket.close()
client端:
import socket
client = socket.socket()
client.connect(('localhost',8899))
while True:
info = input('>>').strip()
if not info:continue
client.send(info.encode('utf-8'))#send发送字节型数据
res = client.recv(1024)
print('res:',res.decode())
client.close()
结果:
四,TCP编程之多用户下载文件
服务端:
import socket
import os
import hashlib
import threading
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.bind(('',8080))
serverSocket.listen(10)
def handle_request(conn):
'''处理客户端的请求'''
while True:
#接收文件名
try:
filename = conn.recv(1024).decode()
if os.path.isfile(filename):
#获取文件大小并发送给客户端
filesize = os.stat(filename).st_size
conn.send(str(filesize).encode('utf-8'))
#防止粘包
respond = conn.recv(1024)
f = open(filename,'rb')
m = hashlib.md5() #生成哈希对象
for line in f:
conn.send(line)
m.update(line) #哈希加密
f.close()
#给客户端发送文件的哈希值
conn.send(str(m.hexdigest()).encode('utf-8'))
print('''----完成一个客户端的下载请求----
下载文件名:%s
大小:%d'''%(filename,filesize))
else:
print('由于不存在文件,拒绝一个客户端请求')
conn.send(b'0')
except Exception as f:
print('a client is lost...')
break
def server():
'''监听客户端的链接'''
while True:
conn, addr = serverSocket.accept()
print('a client connect in...',conn)
t = threading.Thread(target=handle_request,args=(conn,))
t.start()
if __name__ == '__main__':
server()
serverSocket.close()
客户端:
import socket
import hashlib
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('localhost',8080))
while True:
filename = input('你要下载的文件名>>').strip()
if not filename:continue
#发送文件名
client.send(filename.encode('utf-8'))
filesize = client.recv(1024).decode()
if int(filesize):
client.send(b'ready')#防止粘包
f = open(filename,'wb')
m = hashlib.md5() #生成哈希对象
received = 0
filesize = int(filesize)
while received < filesize:
if filesize-received>1024:
size = 1024
else:
size = filesize-received
data = client.recv(size)
m.update(data) #哈希加密
f.write(data)
received += len(data)
else:
f.close()
clientHash = m.hexdigest()
serverHash = client.recv(1024).decode()
print('clientHash:',clientHash)
print('serverHash:',serverHash)
if clientHash==serverHash:
print('下载完成,文件数据完整')
else:
print('文件传输过程存在数据出错')
else:
print('[error] no exist the file')
client.close()
最后结果: