a:创建Socket,涉及到的主要参数有:domain、type、protocal。
domain是协议域,其中AF_INET->IPv4;AF_INET6->IPv6 。
type对应socket类型,SOCK_STREAM->TCP;SOCK_DGRAM->UDP。
protocol是IPPROTO_TCP,若传入0,则会根据第二个参数type,自动选择合适的参数。
b,连接到服务器,主要参数:
客户端socket
指向数据结构socketaddr的指针,其中包括目的端口和IP地址
结构体数据长度
c,发送数据到服务器,主要参数:
客户端socket
发送内容地址
发送内容长度
发送方式标志,一般为0
d,从服务器接受数据,主要参数:
客户端socket
接受内容缓冲区地址
接受内容缓冲区长度
接受方式,0表示阻塞,必须等待服务器返回数据返回值,若成功,则返回读入的字节数,失败则 返回SOCKET_ERROR。
e,关闭socket。
"""
file: service.py
socket service
"""
import socket
import threading
import time
import sys
def socket_service():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 实例化
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #防止socket server重启后端口被占用(socket.error: [Errno 98] Address already in use)
s.bind(('0.0.0.0', 6666)) #bind端口
s.listen(100) #允许连接数
except socket.error as msg:
print(msg)
sys.exit(1)
print('Waiting connection...')
while 1:
conn, addr = s.accept() #阻塞连接
t = threading.Thread(target=deal_data, args=(conn, addr)) #多线程
t.start()
def deal_data(conn, addr):
print('Accept new connection from {0}'.format(addr))
conn.send(('Hi, Welcome to the server!').encode()) #发送响应
while 1:
data = conn.recv(1024)
print('{0} client send data is {1}'.format(addr, data.decode()))
time.sleep(1)
if data == 'exit' or not data: #防止客户断线或异常中断
print('{0} connection close'.format(addr))
conn.send(bytes('Connection closed!'),'UTF-8')
break
"""
reavFull += data #如果客户发送100k数据的处理
if len(reavFull)!=1024*100:
continue
"""
conn.send(bytes('Hello, {0}'.format(data),"UTF-8"))
conn.close()
if __name__ == '__main__':
socket_service()
import socket
import sys
def socket_client():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.101', 6666))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024))#目的在于接受:Accept new connection from (...
while 1:
data = input('please input work: ').encode()
s.send(data)
print('aa',s.recv(1024))
if data == 'exit':
break
s.close()
if __name__ == '__main__':
socket_client()
3、python 实现socket通信代码实例二
进行文件的传输,如,.txt,.jpg等等
服务器端:
###服务器端server.py
import socket
import os
import sys
import struct
def socket_service_image():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# s.bind(('127.0.0.1', 6666))
s.bind(('127.0.0.1', 6666))
s.listen(10)
except socket.error as msg:
print(msg)
sys.exit(1)
print("Wait for Connection.....................")
while True:
sock, addr = s.accept() # addr是一个元组(ip,port)
deal_image(sock, addr)
def deal_image(sock, addr):
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
while True:
fileinfo_size = struct.calcsize('128sq')
print('fileinfo_size is',fileinfo_size)
buf = sock.recv(fileinfo_size) # 接收图片名
print('buf is ',buf)
if buf:
filename, filesize = struct.unpack('128sq', buf)
print('filename ,filesize is',filename.decode(),filesize )
fn = filename.decode().strip('\x00')
print('fn is ',fn)
new_filename = os.path.join('./',
'new_' + fn) # 在服务器端新建图片名(可以不用新建的,直接用原来的也行,只要客户端和服务器不是同一个系统或接收到的图片和原图片不在一个文件夹下)
recvd_size = 0
fp = open(new_filename, 'wb')
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = sock.recv(1024)
recvd_size += len(data)
else:
data = sock.recv(1024)
recvd_size = filesize
print('data is',data)
fp.write(data) # 写入图片数据
fp.close()
sock.close()
break
if __name__ == '__main__':
socket_service_image()
客户端:
'''
Fuction:客户端发送图片和数据
Date:
Author:mxh
'''
###客户端client.py
import socket
import os
import sys
import struct
def sock_client_image():
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 6666)) # 服务器和客户端在不同的系统或不同的主机下时使用的ip和端口,首先要查看服务器所在的系统网卡的ip
# s.connect(('127.0.0.1', 6666)) #服务器和客户端都在一个系统下时使用的ip和端口
except socket.error as msg:
print(msg)
print(sys.exit(1))
filepath = input('input the file: ') # 输入当前目录下的图片名 xxx.jpg
fhead = struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf-8'),
os.stat(filepath).st_size) # 将xxx.jpg以128sq的格式打包
s.send(fhead)
fp = open(filepath, 'rb') # 打开要传输的图片
while True:
data = fp.read(1024) # 读入图片数据
if not data:
print('{0} send over...'.format(filepath))
break
s.send(data) # 以二进制格式发送图片数据
s.close()
# break #循环发送
if __name__ == '__main__':
sock_client_image()
I/O(input/output),即输入/输出端口。每个设备都会有一个专用的I/O地址,用来处理自己的输入输出信息首先什么是I/O:
I/O分为磁盘io和网络io,这里说的是网络io
IO多路复用:
I/O多路复用指:通过一种机制,可以监视多个描述符(socket),一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
Linux
Linux中的 select,poll,epoll 都是IO多路复用的机制。
Linux下网络I/O使用socket套接字来通信,普通I/O模型只能监听一个socket,而I/O多路复用可同时监听多个socket.
I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理.
Python
Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。
对于select模块操作的方法:
句柄列表
11
, 句柄列表
22
, 句柄列表
33
=
select.select(句柄序列
1
, 句柄序列
2
, 句柄序列
3
, 超时时间)
参数: 可接受四个参数(前三个必须)
返回值:三个列表
select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
1
、当 参数
1
序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值
1
序列中
2
、当 参数
2
序列中含有句柄时,则将该序列中所有的句柄添加到 返回值
2
序列中
3
、当 参数
3
序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值
3
序列中
4
、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
5
、当 超时时间 =
1
时,那么如果监听的句柄均无任何变化,则select会阻塞
1
秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行
例子1:
服务端:
sk1 = socket.socket()
sk1.bind(("127.0.0.1",8001))
sk1.listen()
inpu = [sk1,]
while True:
r_list,w_list,e_list = select.select(inpu,[],[],1)
for sk in r_list:
if sk == sk1:
conn,address = sk.accept()
inpu.append(conn)
else:
try:
ret = str(sk.recv(1024),encoding="utf-8")
sk.sendall(bytes(ret+"hao",encoding="utf-8"))
except Exception as ex:
inpu.remove(sk)
客户端
import socket
obj = socket.socket()
obj.connect(('127.0.0.1',8001))
while True:
inp = input("Please(q\退出):\n>>>")
obj.sendall(bytes(inp,encoding="utf-8"))
if inp == "q":
break
ret = str(obj.recv(1024),encoding="utf-8")
print(ret)
例子2:
服务端:
import socket
sk1 = socket.socket()
sk1.bind(("127.0.0.1",8001))
sk1.listen()
inputs = [sk1]
import select
message_dic = {}
outputs = []
while True:
r_list, w_list, e_list = select.select(inputs,[],inputs,1)
print("正在监听的socket对象%d" % len(inputs))
print(r_list)
for sk1_or_conn in r_list:
if sk1_or_conn == sk1:
conn,address = sk1_or_conn.accept()
inputs.append(conn)
message_dic[conn] = []
else:
try:
data_bytes = sk1_or_conn.recv(1024)
data_str = str(data_bytes,encoding="utf-8")
sk1_or_conn.sendall(bytes(data_str+"好",encoding="utf-8"))
except Exception as ex:
inputs.remove(sk1_or_conn)
else:
data_str = str(data_bytes,encoding="utf-8")
message_dic[sk1_or_conn].append(data_str)
outputs.append(sk1_or_conn)
for conn in w_list:
recv_str = message_dic[conn][0]
del message_dic[conn][0]
conn.sendall(bytes(recv_str+"好",encoding="utf-8"))
for sk in e_list:
inputs.remove(sk)
客户端:
import socket
obj = socket.socket()
obj.connect(('127.0.0.1',8001))
while True:
inp = input("Please(q\退出):\n>>>")
obj.sendall(bytes(inp,encoding="utf-8"))
if inp == "q":
break
ret = str(obj.recv(1024),encoding="utf-8")
print(ret)
ESP32代码:
import network
import urequests
import json
import time
d1=10
d2=20
d3='h0101'
while True:
_response = urequests.post("http://www.winvip.top/test/test.php/", headers={"Content-Type":"application/json"}, data=json.dumps({"api_key":"tPmAafaT5Ab3j7F9", "value1":d1, "value2":d2, "value3":d3}))
print(_response.text)
time.sleep(3)
PHP接收post,解析json,更新数据库代码:
connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//插入一个新的数据行
$sql = "INSERT INTO tempdata( date1, date2, date3)
VALUES ('" . $value1 . "', '" . $value2 . "', '" . $value3 . "')";
//更新表中内容
//$sql = mysqli_query($conn,"UPDATE SensorData SET value1 = '".$value1."',value2 = '".$value2."'
// WHERE sensor='Light'");
//如果数据修改成功
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
}
else {
echo "Error: " . $sql . "
" . $conn->error;
}
$conn->close();
}
else {
echo "Wrong API Key provided.
";
}
}
else {
echo "No data posted with HTTP POST.
";
}
?>
PHP数据库查询,显示代码:(以下参考为网上获得,未经测试!!!)
connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//查询数据库bak SensorData表中的内容
$sql = "SELECT id, sensor, location, value1, value2, value3, reading_time FROM SensorData ORDER BY id DESC";
echo '
ID
Sensor
Location
Value 1
Value 2
Value 3
Timestamp
';
if ($result = $conn->query($sql)) {
while ($row = $result->fetch_assoc()) {
$row_id = $row["id"];
$row_sensor = $row["sensor"];
$row_location = $row["location"];
$row_value1 = $row["value1"];
$row_value2 = $row["value2"];
$row_value3 = $row["value3"];
$row_reading_time = $row["reading_time"];
echo '
' . $row_id . '
' . $row_sensor . '
' . $row_location . '
' . $row_value1 . '
' . $row_value2 . '
' . $row_value3 . '
' . $row_reading_time . '
';
}
$result->free();
}
$conn->close();
//
echo ("");
?>