概述
以上传图片到服务器为例子,详细的代码已经上传到github
客户端
1. 初始化socket对象
(1) 创建socket对象(AF_INET, SOCK_STREAM, 0)
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
(2) 与服务器进行连接connect,需要知道服务器的IP和PORT,IP地址的格式(AF_INET),同时要把IP地址和PORT从主机字节序转换为网络字节序。
sockaddr_in servaddr;
servaddr.sin_addr.s_addr = inet_addr((this->mServerIP).c_str());//将主机字节序转为网络字节序
servaddr.sin_port = htons(this->mPort);
std::cout << htons(this->mPort) << std::endl;
servaddr.sin_family = AF_INET;
/*connect操作,返回0则success*/
int socket_init_status = connect(socket_fd, (sockaddr*)&servaddr, sizeof(sockaddr))
2. 用nlohmann把图像从cv::mat转为base64的数据格式,并存到json对象中。
3.发送Json数据(POST方式)
(1) 先发送HTTPHEADER,自己构造头部,一般用到的才加上去,正常来说比如要用到的有:
POST /router HTTP/1.1
CONTENT_TYPE: application/json
CONTENT_LENGTH: xxx
如果上述header中存在参数,则可以用sprintf函数去填写,如以下代码:
const char* header_template =
// Request Line
"POST %s HTTP/1.1rn"
"User-Agent: HANDSOMEBOY 1.0rn"
"Connection: Closern"
"Content-Type: application/jsonrn"
"Content-Length: %lurn"
"rn";
char header[2048] = { 0 };
sprintf(header, header_template, router.c_str(), data_size);
(2) 发送data,将Json数据send过去,若每次send数据的大小 > SEND_BUFFER_SIZE,则可以多次发送,如下代码
if ( data_size < SEND_BUFFER_SIZE) { //在发送data,size小于send_buffer_size
send_size = send(this->socket_fd, json_data.c_str(), data_size, 0);
std::cout << TAG_INFO << "Send Size: " << send_size << " Byte(s)." << std::endl;
} else {
/*
函数c_str()就是将C++的string转化为C的字符串数组,c_str()生成一个constchar*指针,指向字符串的首地址
*/
int total_times = data_size / SEND_BUFFER_SIZE + ((data_size % SEND_BUFFER_SIZE > 0) ? 1 : 0);//计算send次数
for (int i = 0; i < total_times; i++) {
if (i == (total_times-1))
send_size = send(this->socket_fd, json_data.c_str()+i*SEND_BUFFER_SIZE, (data_size-i*SEND_BUFFER_SIZE), 0);
else
send_size = send(this->socket_fd, json_data.c_str()+i*SEND_BUFFER_SIZE, SEND_BUFFER_SIZE, 0);
}
}
4. 接收来自服务端的数据
(1) 使用recv(cli_sockfd, recv_buffer, buffer_size)函数
(2) 处理recv_buffer的数据,通常返回来的数据报报头和data通常由’rnrn’分割,所以将光标移动到’rnrn’的后一位上,此时光标将是json数据开始的位置
Content-Type: application/json
Content-Length: 361
Server: Werkzeug/1.0.0 Python/3.6.10
Date: Wed, 08 Apr 2020 04:00:18 GMT
(这里即是 rnrn)
{
"image_path":"./resources/image/upload/A81F25130C843811393C714496E86062.jpgrn.",
"status_code":200
}
(3) 新建一个buffer来存储data,这里我命名为content_buffer,用strncpy()函数把光标起始位置,到recv_buffer最后位置的数据copy到content_buffer中。
char content_buffer[RECV_BUFFER_SIZE] = {0};
/*strncpy参数:
param1: dataBuffer
param2:取数据地址起始
param3:取数据长度
*/
strncpy(content_buffer, message_ptr+pos, message_size-pos);
//message_ptr是指向recv_buffer开头的指针,而pos是让指针往后移动到data的第一位,
//message_size-pos是指需要截取数据的长度
(4) 通过nlohmann中的parse函数,将content_buffer转为json对象,通过json对象中的status_code字段来确定是否请求成功,若请求成功则正常返回数据并做后续处理
nlohmann::json json_obj = nlohmann::json::parse(content_buffer);
if (200 == json_obj["status_code"].get<int>()) {
find_200 = true;
}
else {
std::cout << "[HTTP ERROR] status_code: " << json_obj["status_code"].get<int>() <<
", message: "<<json_obj["message"].get<std::string>()<< std::endl;
}
//Request success and Receive success
if (find_200) {
return json_obj;
}
服务端(使用的是flask框架)
直接返回return_json似乎有点问题,nlohnmann处理不到,所以return时调用了jsonify,当然也建议使用flask框架返回json数据时使用jsonify。
@app.route('/upload_image', methods=['POST'])
def upload_image():
return_json = {}
if request.method != 'POST':
return_json['status_code'] = 1001
return_json['message'] = 'Request method is Wrong.'
return jsonify(return_json)
# receive data
print('request.content_length:', request.content_length)
print('request.accept_mimetypes:', request.accept_mimetypes)
print('request.user_agent:', request.user_agent)
if request.json is None:
return_json['status_code'] = 1002
return_json['message'] = 'Json data is None.'
return jsonify(return_json)
if request.json['img_num'] <= 0:
return_json['status_code'] = 1003
return_json['message'] = 'Argument 'img_num' of Json date is zero.'
return jsonify(return_json)
# Json data is null or not null
for i in range(request.json['img_num']):
if str(i) + '_img_base64' not in request.json.keys() or request.json[str(i) + '_img_base64'].replace(' ', '') == '':
return_json['status_code'] = 1004
return_json['message'] = 'Argument' + str(i) + ''_img_base64' of Json date does not exists'
' or Invalid base64 string.'
return jsonify(return_json)
# Get json data from request
image_path = ''
for i in range(request.json['img_num']):
path = base64_to_image(request.json[str(i)+'_img_base64'])
image_path = image_path + path + 'rn'
return_json['status_code'] = 200
return_json['image_path'] = image_path
return jsonify(return_json)
最近用C++代码把服务端给写了一下,算是对上面偷懒用python写服务端的小完善,链接在这这是该篇文章的姊妹篇,C++代码编写HTTP服务端
最后
以上就是奋斗睫毛膏为你收集整理的【网络编程】Linux自带socket库构建HTTP客户端发送数据(POST方式)的全部内容,希望文章能够帮你解决【网络编程】Linux自带socket库构建HTTP客户端发送数据(POST方式)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复