先附上慕课的免费学习链接https://www.imooc.com/video/17673
socket是什么
- Socket是电脑网络中进程间数据流的端点
- Socket是操作系统的通信机制
- 应用程序通过Socket进行网络数据的传输
我本人对Socket的理解就是
服务端程序
#首先导入模块,可以用socket.__file__查看文件位置
import socket
#创建实例
sk=socket.socket()
#绑定ip和port,这里指定接受任意ip的连接
ip_port=('0.0.0.0',8888)
#绑定监听,注意这里bind的参数是一个元组
sk.bind(ip_port)
#最大连接数
sk.listen(5)
#提示信息
print("正在等待接收数据.....")
#接收数据
conn,address=sk.accept()
#定义信息
msg="hello world"
#返回信息,python3.x以上网络数据的接受和发送都是byte类型
print("连接地址为",address)
conn.send(msg.encode())
conn.close()
客户端
import socket
#实例初始化
client=socket.socket()
#访问的服务器的ip和端口
ip_port=("127.0.0.1",8888)
#连接主机
client.connect(ip_port)
#接受主机信息,指定最大的数据接受量
data=client.recv(1024)
#打印数据
print(data.decode())
客户端连续消息发送
服务端
#首先导入模块,可以用socket.__file__查看文件位置
import socket
import random
#创建实例
sk=socket.socket()
#绑定ip和port,这里指定接受任意ip的连接
ip_port=('0.0.0.0',8888)
#绑定监听,注意这里bind的参数是一个元组
sk.bind(ip_port)
#最大连接数
sk.listen(5)
#提示信息
print("正在等待接收数据.....")
#接收数据
conn,address=sk.accept()
#定义信息
msg="连接成功"
#返回信息,python3.x以上网络数据的接受和发送都是byte类型
#print("连接地址为",address)
conn.send(msg.encode())
while True:
#接收客户端数据
data=conn.recv(1024)
#打印接收的数据
print(data.decode())
#接收到退出指令,退出循环
if data==b'exit':
break
#发送接收到的数据
conn.send(data)
#发送一个随机数
conn.send(str(random.randint(1,10)).encode())
conn.close()
客户端
import socket
#实例初始化
client=socket.socket()
#访问的服务器的ip和端口
ip_port=("127.0.0.1",8888)
#连接主机
client.connect(ip_port)
#定义一个循环,不断发送消息
while True:
#接受两个主机信息,指定最大的数据接受量
data1=client.recv(1024)
#打印数据
print(data1.decode())
msg_input=input("输入发送的消息: ")
#发送数据
client.send(msg_input.encode())
if msg_input=="exit":
break
data2=client.recv(1024)
print(data2.decode())
注意:这里客户端两个接受命令对应服务端两个send命令,而且注意服务器端和客户端send和recv的顺序,如果一个接收时,另一个一定要发送,否则程序就会一直等待接收数据
socket参数意义
我们先打开python3的socket.py,使用 socket.__file__能找到模板位置,然后我们找到class socket
首先程序进行判断,在fileno为None的时候,family等于AF_INET,type等于SOCK_STREAM,porto等于0,这些参数的含义如下
family:地址族(也就是ip地址类型)
- socket.AF_INET ipv4(默认)
- socket.AF_INET6 ipv6
- socket.AF_UNINX 只能用于单一的Uninx系统进程通信
type:数据传输方式
- socket.SOCK_STREAM 流式socket for tcp(默认)
- socket.SOCK_DGRAM 数据报式socket for UDP
- socket.SOCK_RAW 原始套接字
- socket.SOCK_RDW 可靠UDP形式(UDP传输时可能丢失数据,这里进行数据校验)
- socket.SOCK_SEQPACKET 可靠的连续数据包形式
proto :传输协议
- 0 默认,可以省略
socket非堵塞模块
在上面使用socket模板时,我们只能进行有限个个数的连接,但是这些做到网络通信是不够的,现实中的网络连接不是等待上一个人连接断掉后下一个人才能连接使用,所以我们要想办法做到非堵塞情况。这种情况下就体现出了多线程的好处,每当一个人请求连接,就创建一个线程进行通信,我们用到了新的模块socketserver
服务器端代码如下
import socketserver
import random
class MyServer(socketserver.BaseRequestHandler):
#如果handle方法出现错误,则会跳过
#setup和finish无论如何都会执行
#首先执行setup
def setup(self):
return super().setup()
#然后执行handle
def handle(self):
#定义连接对象
conn=self.request
#定义发送的消息
msg="hello world"
conn.send(msg.encode())
while True:
data=conn.recv(1024)
print(data.decode())
if data==b'exit':
break
conn.send(data)
conn.send(str(random.randint(1,10)).encode())
conn.close()
#最后执行finish
def finish(self):
return super().finish()
if __name__=="__main__":
#创建多线程实例
server=socketserver.ThreadingTCPServer(("127.0.0.1",8888),MyServer)
#开启异步多线程,等待连接
server.serve_forever()
我们可以使用上面的客户端代码进行测试,发现多个客户端窗口可以共同建立连接,达到了非堵塞的目的
python socket实现文件上传
服务器端
import socket
sk=socket.socket()
ip_port=("127.0.0.1",9999)
sk.bind(ip_port)
sk.listen(5)
conn,address=sk.accept()
while True:
with open("file.txt","ab") as f:
data=conn.recv(1024)
if b'quit' in data:
data=data[0:data.find(b'quit')]
f.write(data)
break
f.write(data)
conn.close()
print("上传成功")
客户端
import socket
sk=socket.socket()
ip_port=("127.0.0.1",9999)
sk.connect(ip_port)
#打开文件
with open("1.py","rb") as f:
#按每一段分割文件
for i in f:
#数据上传
sk.send(i)
#发送结束信号
sk.send("quit".encode())
注意,因为客户端的发送数据速度快于服务器端接收速度,所以我们的结束信号在服务器端接收到时与与其他数据夹在一起,所以我们需要把这些夹在一起的数据拆开,把我们需要的写入文件
ps:最后附上一篇非常优秀的文章https://www.jianshu.com/p/066d99da7cbd