Socket网络编程入门详述(2)

步骤:
1.client = socket.socket() 声明实例,生成连接对象
2.client.connect() 与服务器建立连接
3.与服务器交互(发送接收数据)
4.client.close() 断开连接

代码示例:

import socket
"通信案例客户端消息接收与发送"
client = socket.socket() # 声明socket类型,并生成socket连接对象
try:
    client.connect(("localhost",6000)) # 与服务器建立连接

while True:
        msg = input(">>输入要向服务器发送的信息:")
        client.send(msg.encode(encoding="utf-8")) # 向服务器发送信息(只能发送bytes字节类型,不能是str字符类型)
        data = client.recv(1024) # 接收来自服务器的1024个字节
        print("接收来自服务器的数据:",data.decode()) # 打印服务器发送的数据
        chioce = input("按任意键继续,按0退出客户端")
        if chioce == "0":
            client.send(b"000001") # 发送此信号表明客户端要断开连接
            break
        client.close()
except ConnectionRefusedError as e:
    print("服务器还没开机!请静候")

需要注意的是:

1.客户端再发送数据时,要主要服务器接收的大小限制。如果超过了这个限制,超出的部分暂时存在系统缓冲区,第二次接收的时候再输出剩下的部分。例如服务器端的recv(1024),而客户端一次发了2024字节,那么剩下的1000字节存在缓冲区,第二次接收的时候会接收缓冲区的内容,将不会接收新发来的数据,会造成数据错误。官方建议一次性不超过8192字节

2.双发收发数据只能是bytes类型

3.粘包问题,下面讲

socket粘包问题

什么是粘包呢?我们知道发送数据,并且数据量比较大时,并不会一次性发送,即使能一次发送,客户端也不一定能一次性接收,所以服务器有个缓冲区,等客户端下次再接收数据的时候再发送给客户端,所以,就需要将数据分成几次发送,客户端分成几次接收。那又出来问题了,客户端知道数据(文件)有多大么?它怎么知道要接收几次?当然是要服务器告诉他啦!

于是,我们设计服务器首先发送数据大小(数据),再开始分批发送数据,客户端先接收文件大小(数据),再开始分批接收。问题就有可能在这里出现了。如果连续2次send数据,很有可能将两次的数据黏在一起发送出去,在客户端也无法将其分开,怎么办呢?

我们可以让服务器每次发送数据后,接收来自客户端的确认,这样会强制清空缓冲区,就不会造成粘包。当然,基于上面讲的方法,只需要在发送正式数据之前接收确认就好。

最后,如果希望100%确认双发收发数据是否一致,可以采用MD5校验。

服务器端步骤:

1.读取文件名
2.检测文件是否存在
3.打开文件
4.检测文件大小
5.将文件大小发给客户端
6.确认
7.开始边读边发(循环发送)
8.发送MD5

代码:

import socket,os,hashlib

ser = socket.socket()
ser.bind(("localhost",5000))
ser.listen()

while True:
    try:
        print("正在等待客户端连接...")
        conn,addr = ser.accept()
        print("已连接,new conn:",addr)
        while True:
            data = conn.recv(8192)
            filename = data.decode()
            print("寻找文件",filename)
            if os.path.isfile(filename):
                conn.send(b"01")
                conn.recv(1024)
                f = open(filename,"rb")
                m = hashlib.md5()
                file_size = os.stat(filename).st_size
                conn.send(str(file_size).encode(encoding="utf-8"))
                client_ack = conn.recv(1024)  # 接收确认信息
                if client_ack == b"1":
                    print("开始发送数据")
                for line in f:
                    m.update(line)
                    conn.send(line)
                f.close()
                conn.send(m.hexdigest().encode(encoding="utf-8")) # 发送MD5值
            else:
                conn.send(b"00") #表示文件不存在
                print("该文件不存在!")
    except ConnectionResetError:
        print("该客户端已断开连接")


ser.close()
print("服务器已关闭")

客户端步骤:

1.发送接收文件请求,同时将文件名发送给服务器

2.接收文件长度

3.本地新建同名文件,循环接收数据,并将其写入文件

4.同时更新本地MD5值

5.接收数据完毕后,再接收服务器的MD5值,与本地MD5值进行比较

代码:

import socket,hashlib

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b130bc226d7878225720dc78772dade2.html