Note3:TCP编程

一,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()

最后结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值