10.socket网络编程
套接字工作流程

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
Socket Families(地址簇)
socket.AF_UNIX unix本机进程间通信
socket.AF_INET IPV4
socket.AF_INET6 IPV6
Socket Types
socket.SOCK_STREAM #for tcp
socket.SOCK_DGRAM #for udp
Socket 参数
s.bind(address) 绑定(host,port)
s.listen(backlog) 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量
s.accept() 接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
s.connect(address) address的格式为元组(hostname,port)
s.setblocking(bool) 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。
s.close() 关闭套接字
s.recv(bufsize) bufsize指定最多可以接收的数量
s.send(string) 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。
s.sendall(string) 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
内部通过递归调用send,将所有内容发送出去。
s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在
刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )
s.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)
服务端
- 创建socket对象
- 绑定IP和端口 绑定 bind()
- 开始监听链接 监听 listen()
- 阻塞 , 等待客户端成功连接 阻塞 accept()
- 接收请求数据 接收 recv()
- 处理并发送请求数据 发送 send()
- 关闭 close()
客户端
- 创建socket对象
- 连接服务端 , 按照IP和端口连接 连接 connet()
- 发送请求数据 发送 send()
- 接收请求数据 接收 recv()
- 关闭 close()
简单socket
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 重用ip和端口 ,但其它client只是挂起状态。只有一个能交互
import socket
# 创建socket对象
sock = socket.socket()
# 绑定IP和端口,参数是一个元组(ip,port)
sock.bind(('localhost', 8080))
# 开始监听,最大挂起5个
sock.listen(5)
# 阻塞,等待连接
conn,addr = sock.accept()
# 接收请求数据,接收大小为1024字节
content = conn.recv(1024)
print(content.decode())
# 发送请求结果,必须以bytes类型
conn.send(b'jieshouwanbi')
# 关闭链接
conn.close()
import socket
# 创建socket对象
sock = socket.socket()
# 建立链接
sock.connect(('localhost', 8080))
# 发送请求数据,必须以bytes类型
sock.send(b"hello")
# 接收请求结果
content = sock.recv(1024)
print(content.decode())
# 关闭套接字
sock.close()
SSH
1 import socket ,os
2 server = socket.socket() #创建socket对象
3 server.bind(('localhost',9999) ) #绑定ip和port
4 server.listen() #开始监听
5
6 while True:
7 conn, addr = server.accept() #阻塞 等待连接
8 print("new conn:",addr)
9 while True:
10 print("等待新指令")
11 data = conn.recv(1024) #接收客户端发过来的命令
12 if not data:
13 break
14 print("执行指令:",data)
15 cmd_res = os.popen(data.decode()).read() #执行客户端发过来的命令,返回信息长度(接收字符串,执行结果也是字符串)
16 print("before send",len(cmd_res)) #信息的长度
17 if len(cmd_res) ==0:
18 cmd_res = "cmd has no output..."
19
20 conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先发命令执行的结果信息大小给客户端
21 client_ack = conn.recv(1024) #防止粘包,客户端ack
22 conn.send(cmd_res.encode("utf-8")) #发送信息
23 print("send done")
24
25 server.close()
1 import socket
2 client = socket.socket()
3 client.connect(('localhost',9999))
4
5 while True:
6 cmd = input(">>:").strip() #输入命令
7 if len(cmd) == 0: continue
8 client.send(cmd.encode("utf-8")) #发送命令给server端
9 cmd_res_size = client.recv(1024) #接受server端发过来的命令结果信息长度
10 print("命令结果大小:",cmd_res_size)
11 client.send("准备接受".encode('utf-8')) #防止粘包
12 received_size = 0 #已经接受数据的大小
13 received_data = b''
14 while received_size < int(cmd_res_size.decode()):
15 data = client.recv(1024) #只要小于,就一直接收
16 received_size += len(data) #每次收到的有可能小于1024,所以
17 必须用len判断
18 #print(data.decode())
19 received_data += data
20 else:
21 print("cmd res receive done...",received_size)
22 print(received_data.decode())
23
24
25 client.close()
ftp传文件
ftp server
1. 读取文件名
2. 检测文件是否存在
3. 打开文件
4. 检测文件大小
5. 发送文件大小给客户端
6. 等客户端确认
7. 开始边读边发数据
8. 发送md5
1 import socket ,os
2 server = socket.socket()
3 server.bind(('localhost',9999))
4 server.listen()
5
6 while True:
7 conn, addr = server.accept()
8 print("new conn:",addr)
9 while True:
10 print("等待新指令")
11 data = conn.recv(1024)
12 if not data:
13 print("客户端已断开")
14 break
15 cmd,filename = data.decode().split()
16 print(filename)
17 if os.path.isfile(filename): #判断是否是文件
18 f = open(filename,"rb") #打开文件
19 file_size = os.stat(filename).st_size #文件大小
20 conn.send( str(file_size).encode() ) #send file size 防止粘包
21 conn.recv(1024) #wait for ack
22 for line in f:
23 conn.send(line) #开始发送
24 f.close()
25 print("send done")
26
27 server.close()
1 import socket
2 import hashlib
3 client = socket.socket()
4 client.connect(('localhost', 9999))
5
6 while True:
7 cmd = input(">>:").strip()
8 if len(cmd) == 0: continue
9
10 if cmd.startswith("get"): #判断是否以字符串‘get’ 开头
11 client.send(cmd.encode()) #把需要下载的文件发给server端
12 server_response = client.recv(1024) #接收server端发过来的文件大小
13 print("servr response:", server_response) #打印文件大小
14 client.send(b"ready to recv file") #防止粘包
15 file_total_size = int(server_response.decode())
16 received_size = 0 #已经接收的大小
17 filename = cmd.split()[1]
18 f = open(filename + ".new", "wb") #创建新文件 用于保存
19
20 while received_size < file_total_size:
21 if file_total_size - received_size > 1024: # 要收不止一次
22 size = 1024
23 else: # 最后一次了,剩多少收多少
24 size = file_total_size - received_size
25 print("last receive:", size)
26
27 data = client.recv(size)
28 received_size += len(data)
29 f.write(data)
30 # print(file_total_size,received_size)
31 else:
32 print("file recv done", received_size, file_total_size)
33 f.close()
34 client.close()
1 import hashlib
2 import socket ,os,time
3 server = socket.socket()
4 server.bind(('localhost',9999))
5 server.listen()
6 while True:
7 conn, addr = server.accept()
8 print("new conn:",addr)
9 while True:
10 print("等待新指令")
11 data = conn.recv(1024)
12 if not data:
13 print("客户端已断开")
14 break
15 cmd,filename = data.decode().split()
16 print(filename)
17 if os.path.isfile(filename):
18 f = open(filename,"rb")
19 m = hashlib.md5()
20 file_size = os.stat(filename).st_size
21 conn.send( str(file_size).encode() ) #send file size
22 conn.recv(1024) #wait for ack
23 for line in f:
24 m.update(line)
25 conn.send(line)
26 print("file md5", m.hexdigest())
27 f.close()
28 conn.send(m.hexdigest().encode()) #send md5
29 print("send done")
30
31 server.close()
1 import socket
2 import hashlib
3 client = socket.socket()
4 client.connect(('localhost', 9999))
5
6 while True:
7 cmd = input(">>:").strip()
8 if len(cmd) == 0: continue
9 if cmd.startswith("get"):
10 client.send(cmd.encode())
11 server_response = client.recv(1024)
12 print("servr response:", server_response)
13 client.send(b"ready to recv file")
14 file_total_size = int(server_response.decode())
15 received_size = 0
16 filename = cmd.split()[1]
17 f = open(filename + ".new", "wb")
18 m = hashlib.md5()
19
20 while received_size < file_total_size:
21 if file_total_size - received_size > 1024: # 要收不止一次
22 size = 1024
23 else: # 最后一次了,剩多少收多少
24 size = file_total_size - received_size
25 print("last receive:", size)
26
27 data = client.recv(size)
28 received_size += len(data)
29 m.update(data)
30 f.write(data)
31 print(file_total_size,received_size)
32 else:
33 new_file_md5 = m.hexdigest()
34 print("file recv done", received_size, file_total_size)
35 f.close()
36 server_file_md5 = client.recv(1024)
37 print("server file md5:", server_file_md5)
38 print("client file md5:", new_file_md5)
39
40 client.close()
- 我的WCF之旅(4):WCF中的序列化[上篇]
- WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]
- 微信年度重磅“小游戏”上线,罗胖一度退出的小程序正在逆袭
- 谈谈WCF中的Data Contract(2):WCF Data Contract对Generic的支持
- Android注解学习(1)
- [WCF权限控制]ASP.NET Roles授权[上篇]
- [WCF权限控制]ASP.NET Roles授权[下篇]
- 如何解决分布式系统中的跨时区问题[实例篇]
- Visual Studio对程序集签名时一个很不好用的地方
- 一个关于解决序列化问题的编程技巧
- [WCF权限控制]从两个重要的概念谈起:Identity与Principal[上篇]
- 从数据到代码——通过代码生成机制实现强类型编程[下篇]
- 谈谈你最熟悉的System.DateTime[下篇]
- 如何解决EnterLib异常处理框架最大的局限——基于异常"类型"的异常处理策略
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Ubuntu20.04安装Python3的虚拟环境教程详解
- Android编程实现播放视频时切换全屏并隐藏状态栏的方法
- Android UI设计与开发之仿人人网V5.9.2最新版引导界面
- PopupWindow使用方法详解
- Android 中cookie的处理详解
- Android UI设计与开发之ViewPager仿微信引导界面以及动画效果
- Android UI设计与开发之ViewPager介绍和简单实现引导界面
- Android RollPagerView实现轮播图
- Android UI设计与开发之使用ViewPager实现欢迎引导页面
- Android ListView里控件添加监听方法的实例详解
- Android实现底部图片选择Dialog
- AndroidImageSlider实现炫酷轮播广告效果
- Android获取手机本机号码的实现方法
- Android中RecyclerView的item宽高问题详解
- Andoroid实现底部图片选择Dialog效果