Lost buffer data on TCP server.

mattfox

问题描述

I created TCP server, for some reason when 2012 bytes are sent to the server, the server only accepts 137 of them, as a result of which I don't receive a full request and cannot give a responses to client. All data is transmitted to the server encrypted base64.

This is a correct buffer (send 240 bytes):

POST /data HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Content-Length: 240
Host: 127.0.0.1:2222

ODkyMTk4NzAtYWViNC00ZDczLWEzYjUtMWZiMDNjZjJhNzQwIpnr4WD5VcTW7Zs4lb9wVk7+gOB5pGyhBn/0rLAeY281seIOLVXEC0yFa1NrgP6K7zayVvuIeQETIkUljZTAGYOZrCBC29fFOAftvnCzutmo9onYnG3c03ZF1knxuE5hWh1/y5XxYV1mCA5lisvkJskPu9dDFZ7IyDS6+0Luox17udJpVRDCP6/e0Ur7PrOf

This is incorrect buffer (send 2012 bytes):

POST /data HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Pragma: no-cache
Content-Length: 2012
Host: 127.0.0.1:2222

Where here body?
Note the Content-Length of the header, i.e. the server accepts the correct Content-Length in the header, but why does it lose the request body?

程序代码或配置

use Workerman\Worker;

require_once('./vendor/autoload.php');

// Create socket and listen port
$worker = new Worker('tcp://127.0.0.1:2222');

// 4 processes
$worker->count = 4;

// Emitted when new connection come
$worker->onConnect = function ($connection) {
    echo PHP_EOL."New connection".PHP_EOL;
};

// Emitted when data received
$worker->onMessage = function ($connection, $data) {
    var_dump($data);
    $connection->close();
};

// Emitted when connection is closed
$worker->onClose = function ($connection) {
    echo PHP_EOL."Connection closed".PHP_EOL;
};

Worker::runAll();

重现问题的步骤

  1. Create a TCP server.
  2. Try to send more than 1024 bytes.
  3. Try to receive all bytes on the onMessage function.

操作系统环境及workerman/webman等具体版本

Lates version of workerman.

551 2 0
2个回答

admin

你是用的是tcp://0.0.0.0

你必须要手动截取 包的段落在 input协议里,return tcp packetLength,否则第二次tcp包过来的时候就会混乱。

如果你需要http协议,请用http://0.0.0.0
或者使用webman框架

https://www.workerman.net/doc/workerman/protocols/how-protocols.html

  • mattfox 2023-04-07

    Hi! thanks for reply.
    Could you please share an example of what I need to change in the code so that I can accept the full data?
    Unfortunately, we cannot use the HTTP protocol, since the Windows program refers to us in this way...

    Thanks a lot!

six
use Workerman\Worker;

require_once('./vendor/autoload.php');

// Create socket and listen port
$worker = new Worker('http://127.0.0.1:2222'); // Here use http if your client is a http client

// 4 processes
$worker->count = 4;

// Emitted when new connection come
$worker->onConnect = function ($connection) {
    echo PHP_EOL."New connection".PHP_EOL;
};

// Emitted when data received
$worker->onMessage = function ($connection, $request) {
    //var_dump((string)$request);
    var_dump($request->rawBody());
    $connection->close('ok');
};

// Emitted when connection is closed
$worker->onClose = function ($connection) {
    echo PHP_EOL."Connection closed".PHP_EOL;
};

Worker::runAll();
  • mattfox 2023-04-07

    Hi, thanks. But don't work for me. In this construction var_dump($request->rawBody); I had an error is NULL.
    But I send to server 240 bytes.

  • six 2023-04-07

    My mistake, it should be $request->rawBody()

  • mattfox 2023-04-07

    Amazing this is work for me! So but can make this for tcp protocol?

  • six 2023-04-07

    TCP is a transport layer protocol that is stream based and has no data boundaries, requiring manual collection of all data and splitting of requests from it. And HTTP is an application layer protocol based on TCP, which can split requests in the TCP data stream.

  • mattfox 2023-04-08

    Yes, I understand it, but technically in a worker you can get the full amount of data from TCP protocol? If yes - how can I do this then I get onMessage event?

  • six 2023-04-08
    use Workerman\Worker;
    
    require_once('./vendor/autoload.php');
    
    // Create socket and listen port
    $worker = new Worker('tcp://127.0.0.1:2222');
    
    // 4 processes
    $worker->count = 4;
    
    // Emitted when new connection come
    $worker->onConnect = function ($connection) {
        echo PHP_EOL."New connection".PHP_EOL;
    };
    
    // Emitted when data received
    $worker->onMessage = function ($connection, $buffer) {
        $connection->receivedBuffer = ($connection->receivedBuffer ?? '') . $buffer;
        echo "onMessage Emitted and all buffer now is:\n $connection->receivedBuffer";
        if (your_check_request_complete_func($connection->receivedBuffer)) {
            echo "Got a complete request\n $connection->receivedBuffer";
            $connection->receivedBuffer =  '';
        }
    };
    
    // Emitted when connection is closed
    $worker->onClose = function ($connection) {
        echo PHP_EOL."Connection closed".PHP_EOL;
    };
    
    Worker::runAll();

    TCP has no data boundaries that means onMessage may emitted many times you should collect all buffer and check if it a complete request.

年代过于久远,无法发表回答
🔝