本地回环地址
127.0.0.1
我们先来写一个简单地服务器和客户端
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8080
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
conn.send(b
"hello"
)
# 给别人回话
conn.close()
# 挂断电话
server.close()
# 关机
|
1
2
3
4
5
6
7
8
9
10
11
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8080
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
date
=
client.recv(
1024
)
#接收别人说话,没次接收1024个字节
print
(date)
client.close()
# 挂电话
|
注意,在我们写服务器与客户端的时候
send与recv必须要一一对应
不能出现两边都相同的
recv是跟内存要数据,至于数据的来源你无需考虑
粘包
我们来看下面的的代码
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8088
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
conn.close()
# 挂断电话
server.close()
# 关机
|
客户端
1
2
3
4
5
6
7
8
9
10
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8088
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
client.send(b
"hello"
)
# 对别人发消息
client.close()
# 挂电话
|
服务端打印结果
1
|
b
'hellohello'
|
这是应为;
tcp协议会将时间间隔短的,和文件大小小的会一次打包发个对方
如果我们将代码改一下,将服务端收到的字节数1024改为我们知道的字节数,看看是否还会粘包
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8088
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
5
)
# 听别人说话,接收1023个字节数
print
(date)
date
=
conn.recv(
5
)
# 听别人说话,接收1023个字节数
print
(date)
conn.close()
# 挂断电话
server.close()
# 关机
|
客户端
1
2
3
4
5
6
7
8
9
10
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8088
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
client.send(b
"hello"
)
# 对别人发消息
client.close()
# 挂电话
|
打印结果
1
2
|
b
'hello'
b
'hello'
|
在我们知道了,我么传输的文件大小是多大的时候,规定给接收数据的recv就会避免粘包
解决粘包问题
struct模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
import
struct
print
(
"--------------------------1--------------------------"
)
msg
=
"asdasdasdasdasd"
print
(
"原字符串的长度"
)
print
(
len
(msg))
handler
=
struct.pack(
"i"
,
len
(msg))
print
(
"创建报头的长度"
)
print
(
len
(handler))
res
=
struct.unpack(
"i"
,handler)[
0
]
print
(
"解报头过后的长度"
)
print
(res)
print
(
"--------------------------2--------------------------"
)
msg1
=
"asdasdasdasdasdasdasdasd"
print
(
"原字符串的长度"
)
print
(
len
(msg1))
handler1
=
struct.pack(
"i"
,
len
(msg1))
print
(
"创建报头的长度"
)
print
(
len
(handler1))
res1
=
struct.unpack(
"i"
,handler1)[
0
]
print
(
"解报头过后的长度"
)
print
(res1)
"""
--------------------------1--------------------------
原字符串的长度
15
创建报头的长度
4
解报头过后的长度
15
--------------------------2--------------------------
原字符串的长度
24
创建报头的长度
4
解报头过后的长度
24
"""
|
经过观察这个模块会将自己的长度固定为4,8几个等级,我们一般选i就够用了
我们就可以将这个发过去,解报头,就可以知道原来的数据的字节大小
如果这个字节大小比我们接收的大
我们就然他一直接收,直达接收完为止
代码如下
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import
socket
import
subprocess
import
json
import
struct
# 创建套接字
server
=
socket.socket()
# 绑定端口号,及IP地址
server.bind((
"127.0.0.1"
,
8181
))
# 进入半连接池状态
server.listen(
5
)
while
True
:
conn, address
=
server.accept()
# 等待客户端连接
while
True
:
# 判断是否会出错
try
:
date
=
conn.recv(
1024
).decode(
"utf-8"
)
# 接收客户端发来的数据
if
len
(date)
=
=
0
:
break
# 判断客户端发来的数据是否为空,为空就退出循环,关闭这个通道
# 创建一个subprocess的对象
obj
=
subprocess.Popen(date, shell
=
True
, stdout
=
subprocess.PIPE, stderr
=
subprocess.PIPE)
# 将对象拿到的类容做个合并
res
=
obj.stdout.read()
+
obj.stderr.read()
# 创建一个字典,将拿到的数据的字符数,装入字典中
dic
=
{
"file_size"
:
len
(res)}
# 将字典数据类型,转换为json的字符串数据类型
json_dic
=
json.dumps(dic)
# 将json字符串数据类型,创建为报头
handler
=
struct.pack(
"i"
,
len
(json_dic))
# 发送报头
conn.send(handler)
# 发送json字符串的字典
conn.send(json_dic.encode(
"utf-8"
))
# 发送原始数据
conn.send(res)
# 捕捉异常
except
ConnectionResetError:
break
# 关闭通道
conn.close()
|
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import
socket
import
struct
import
json
# 创键套接字
client
=
socket.socket()
# 绑定端口和IP地址
client.connect((
"127.0.0.1"
,
8181
))
while
True
:
# 用户输入发送内容,并装换成2进制
msg
=
input
(
"cmd>>>"
).strip().encode(
"utf-8"
)
# 判断用户输入是否为空,为空跳过本次循环
if
len
(msg)
=
=
0
:
continue
# 发送数据
client.send(msg)
# 接收报头
handler
=
client.recv(
4
)
# 解析报头,注意必须加索引,拿到json过后的字典的字节数
json_dic_size
=
struct.unpack(
"i"
, handler)[
0
]
# 接收json字典的字节数的json字典
json_dic
=
client.recv(json_dic_size)
# 将json数据的字典,反序列化
dic
=
json.loads(json_dic)
# 定义一个字节数为0 的变量
msg_size
=
0
# 定义一个空的2进制字符
msg_date
=
b''
# 判断,如果定义的字节数小于我们字典中的字节数就读取文件,如果等于和大于就退出循环,打印文件类容
while
msg_size < dic.get(
"file_size"
):
date
=
client.recv(
1024
)
# 文件类容累加
msg_date
+
=
date
# 字节数累加
msg_size
+
=
len
(date)
print
(msg_date.decode(
"gbk"
))
|
本地回环地址
127.0.0.1
我们先来写一个简单地服务器和客户端
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8080
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
conn.send(b
"hello"
)
# 给别人回话
conn.close()
# 挂断电话
server.close()
# 关机
|
1
2
3
4
5
6
7
8
9
10
11
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8080
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
date
=
client.recv(
1024
)
#接收别人说话,没次接收1024个字节
print
(date)
client.close()
# 挂电话
|
注意,在我们写服务器与客户端的时候
send与recv必须要一一对应
不能出现两边都相同的
recv是跟内存要数据,至于数据的来源你无需考虑
粘包
我们来看下面的的代码
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8088
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
date
=
conn.recv(
1024
)
# 听别人说话,接收1023个字节数
print
(date)
conn.close()
# 挂断电话
server.close()
# 关机
|
客户端
1
2
3
4
5
6
7
8
9
10
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8088
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
client.send(b
"hello"
)
# 对别人发消息
client.close()
# 挂电话
|
服务端打印结果
1
|
b
'hellohello'
|
这是应为;
tcp协议会将时间间隔短的,和文件大小小的会一次打包发个对方
如果我们将代码改一下,将服务端收到的字节数1024改为我们知道的字节数,看看是否还会粘包
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
socket
server
=
socket.socket()
# 就比如买了一个手机
server.bind((
"127.0.0.1"
,
8088
))
# bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机
server.listen(
5
)
# 半连接池,最大等待连接数为5个,就比如开机
conn,address
=
server.accept()
# 接听电话等着别人给你打电话
date
=
conn.recv(
5
)
# 听别人说话,接收1023个字节数
print
(date)
date
=
conn.recv(
5
)
# 听别人说话,接收1023个字节数
print
(date)
conn.close()
# 挂断电话
server.close()
# 关机
|
客户端
1
2
3
4
5
6
7
8
9
10
|
import
socket
client
=
socket.socket()
#拿电话
client.connect((
"127.0.0.1"
,
8088
))
#绑定的是IP地址和端口号,也是一个元组 拨号
client.send(b
"hello"
)
# 对别人发消息
client.send(b
"hello"
)
# 对别人发消息
client.close()
# 挂电话
|
打印结果
1
2
|
b
'hello'
b
'hello'
|
在我们知道了,我么传输的文件大小是多大的时候,规定给接收数据的recv就会避免粘包
解决粘包问题
struct模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
import
struct
print
(
"--------------------------1--------------------------"
)
msg
=
"asdasdasdasdasd"
print
(
"原字符串的长度"
)
print
(
len
(msg))
handler
=
struct.pack(
"i"
,
len
(msg))
print
(
"创建报头的长度"
)
print
(
len
(handler))
res
=
struct.unpack(
"i"
,handler)[
0
]
print
(
"解报头过后的长度"
)
print
(res)
print
(
"--------------------------2--------------------------"
)
msg1
=
"asdasdasdasdasdasdasdasd"
print
(
"原字符串的长度"
)
print
(
len
(msg1))
handler1
=
struct.pack(
"i"
,
len
(msg1))
print
(
"创建报头的长度"
)
print
(
len
(handler1))
res1
=
struct.unpack(
"i"
,handler1)[
0
]
print
(
"解报头过后的长度"
)
print
(res1)
"""
--------------------------1--------------------------
原字符串的长度
15
创建报头的长度
4
解报头过后的长度
15
--------------------------2--------------------------
原字符串的长度
24
创建报头的长度
4
解报头过后的长度
24
"""
|
经过观察这个模块会将自己的长度固定为4,8几个等级,我们一般选i就够用了
我们就可以将这个发过去,解报头,就可以知道原来的数据的字节大小
如果这个字节大小比我们接收的大
我们就然他一直接收,直达接收完为止
代码如下
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import
socket
import
subprocess
import
json
import
struct
# 创建套接字
server
=
socket.socket()
# 绑定端口号,及IP地址
server.bind((
"127.0.0.1"
,
8181
))
# 进入半连接池状态
server.listen(
5
)
while
True
:
conn, address
=
server.accept()
# 等待客户端连接
while
True
:
# 判断是否会出错
try
:
date
=
conn.recv(
1024
).decode(
"utf-8"
)
# 接收客户端发来的数据
if
len
(date)
=
=
0
:
break
# 判断客户端发来的数据是否为空,为空就退出循环,关闭这个通道
# 创建一个subprocess的对象
obj
=
subprocess.Popen(date, shell
=
True
, stdout
=
subprocess.PIPE, stderr
=
subprocess.PIPE)
# 将对象拿到的类容做个合并
res
=
obj.stdout.read()
+
obj.stderr.read()
# 创建一个字典,将拿到的数据的字符数,装入字典中
dic
=
{
"file_size"
:
len
(res)}
# 将字典数据类型,转换为json的字符串数据类型
json_dic
=
json.dumps(dic)
# 将json字符串数据类型,创建为报头
handler
=
struct.pack(
"i"
,
len
(json_dic))
# 发送报头
conn.send(handler)
# 发送json字符串的字典
conn.send(json_dic.encode(
"utf-8"
))
# 发送原始数据
conn.send(res)
# 捕捉异常
except
ConnectionResetError:
break
# 关闭通道
conn.close()
|
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import
socket
import
struct
import
json
# 创键套接字
client
=
socket.socket()
# 绑定端口和IP地址
client.connect((
"127.0.0.1"
,
8181
))
while
True
:
# 用户输入发送内容,并装换成2进制
msg
=
input
(
"cmd>>>"
).strip().encode(
"utf-8"
)
# 判断用户输入是否为空,为空跳过本次循环
if
len
(msg)
=
=
0
:
continue
# 发送数据
client.send(msg)
# 接收报头
handler
=
client.recv(
4
)
# 解析报头,注意必须加索引,拿到json过后的字典的字节数
json_dic_size
=
struct.unpack(
"i"
, handler)[
0
]
# 接收json字典的字节数的json字典
json_dic
=
client.recv(json_dic_size)
# 将json数据的字典,反序列化
dic
=
json.loads(json_dic)
# 定义一个字节数为0 的变量
msg_size
=
0
# 定义一个空的2进制字符
msg_date
=
b''
# 判断,如果定义的字节数小于我们字典中的字节数就读取文件,如果等于和大于就退出循环,打印文件类容
while
msg_size < dic.get(
"file_size"
):
date
=
client.recv(
1024
)
# 文件类容累加
msg_date
+
=
date
# 字节数累加
msg_size
+
=
len
(date)
print
(msg_date.decode(
"gbk"
))
|