Boost::Asio写锁

Boost::Asio write lock

我有一个基于 TCP/IP 连接的 client/server 的简单实现。

客户端通过套接字连接到服务器发送一些数据然后接收一些数据。 以下是写在c++/Linux boost.asio

上的我的服务器的实现
#include <ctime>
#include <iostream>

#include <string>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;
std::string make_daytime_string()
{
    using namespace std; // For time_t, time and ctime;
    time_t now = time(0);
    return ctime(&now);
}
std::string make_response()
{
    std::string response;
    response.clear();
    std::cout<< "*****************************************"<< endl;
    response = "HTTP/1.1 200 OK\n" ;
    response += "Transfer-Encoding: chunked\n";
    response += "Date: " + make_daytime_string();
    response += "Content-Type: text/plain;";
    std::cout << response << endl;
    std::cout<<"*****************************************"<<endl;
    return response;

}
void on_read( const boost::system::error_code& error, std::size_t bytes_transferred)
{

}

int main(int argc, char argv[])
{
    try
    {

        if(argc != 3)
        {
            std::cout << "invalid number of arguments" <<  endl;
            std::cout << "<sock.exe> <port> <status code>" << endl;
            return 1;
        }
        boost::asio::io_service io_service;

        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1313));
        std::cout << "listening on port" << endl;

        for (;;)
        {

            tcp::socket socket(io_service);
            acceptor.accept(socket);


            std::string message;

            boost::system::error_code ignored_error;

            boost::asio::streambuf response;
            boost::array<char, 5024> buffer;
            buffer.assign(0);// clearing array

            std::ostringstream ss;

            boost::asio::read_until(socket, response, "\n");

            std::string s( (std::istreambuf_iterator<char>(&response)), std::istreambuf_iterator<char>() );

            std::cout << "\n\nPeer IP: " << socket.remote_endpoint().address().to_string() << std::endl;
            std::cout << "---------------------------------------------" << endl;

            std::cout  << s <<endl;
            std::cout << "---------------------------------------------" << endl;
            message.clear();
            cout << "writing response" << endl;
            message = make_response();

            boost::asio::write(socket, boost::asio::buffer(message, sizeof(message)));
            cout << "ended writing"<< endl;

        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

我连接的客户端使用 .Net 和 C#

实现如下
 private static void sendWebRequest()
        {

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.17.85:1313/RestBaby");
            req.Method = "POST";
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.MaxServicePointIdleTime = 2000;
            req.KeepAlive = true;
            string postData = "This is a test that posts this string to a Web server.";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Set the ContentType property of the WebRequest.
            req.ContentType = "application/x-www-form-urlencoded";
            // Set the ContentLength property of the WebRequest.
            req.ContentLength = byteArray.Length;

            // Get the request stream.
            Stream dataStream = req.GetRequestStream();
            // Write the data to the request stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Close the Stream object.
            dataStream.Close();
            WebResponse rep = req.GetResponse();
        }

我遇到的问题是客户端发送的数据在服务端很容易解析并且cout写函数也被调用了,但是在客户端出现了异常

The underlying connection was closed: The connection was closed unexpectedly.

很多地方都错了。

  • 您的代码中有大量未使用的东西;解开迷惑!
  • 你不了解HTTP协议。它显示是因为您不使用 CRLF 行结束,也不要以双 CRLF 结束响应
  • 您正在响应中发送 sizeof(std::string) 个字节:

    boost::asio::write(socket, boost::asio::buffer(message, sizeof(message)));
    

    使用 std::string:

    的便利重载来消除混淆
    boost::asio::write(socket, boost::asio::buffer(message));
    

如果您承诺发送分块编码,则需要实施分块编码(我暂时删除 header 并添加 Content-Length: 0)。

Live On Coliru 针对您的 client.cs 进行了测试(见下文)

#include <ctime>
#include <iostream>

#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>

using boost::asio::ip::tcp;
using namespace std;
std::string make_daytime_string()
{
    using namespace std; // For time_t, time and ctime;
    time_t now = time(0);
    return ctime(&now);
}
std::string make_response()
{
    std::string response = "HTTP/1.1 200 OK\r\n";
    //response += "Transfer-Encoding: chunked\r\n";
    response += "Date: " + make_daytime_string();
    response += "Content-Length: 0\r\n";
    response += "Content-Type: text/plain;\r\n\r\n";
    return response;
}
void on_read(const boost::system::error_code& error, std::size_t bytes_transferred) {}

int main()
{
    try {
        boost::asio::io_service io_service;

        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 1313));
        std::cout << "listening on port 1313" << endl;

        for (;;) {
            tcp::socket socket(io_service);
            acceptor.accept(socket);


            boost::system::error_code ignored_error;

            boost::asio::streambuf request;
            boost::asio::read_until(socket, request, "\r\n\r\n");

            std::cout << "\n\nPeer IP: " << socket.remote_endpoint().address().to_string() << std::endl;
            std::cout << "---------------------------------------------" << endl;

            std::cout << &request << endl;
            std::cout << "---------------------------------------------" << endl;

            cout << "writing response" << endl;
            boost::asio::write(socket, boost::asio::buffer(make_response()));
            cout << "ended writing" << endl;
        }
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

和对应的Client.cs

using System.Web;
using System.Net;
using System.Text;
using System.IO;
using System;

public class Program {
    public static void Main(string[] args) {
        sendWebRequest();
    }

    private static void sendWebRequest() {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://localhost:1313/RestBaby");
        req.Method = "POST";
        ServicePointManager.Expect100Continue = false;
        ServicePointManager.MaxServicePointIdleTime = 2000;
        req.KeepAlive = true;
        string postData = "This is a test that posts this string to a Web server.";
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        // Set the ContentType property of the WebRequest.
        req.ContentType = "application/x-www-form-urlencoded";
        // Set the ContentLength property of the WebRequest.
        req.ContentLength = byteArray.Length;

        // Get the request stream.
        Stream dataStream = req.GetRequestStream();
        // Write the data to the request stream.
        dataStream.Write(byteArray, 0, byteArray.Length);
        // Close the Stream object.
        dataStream.Close();
        WebResponse rep = req.GetResponse();
    }
}