簡體   English   中英

UNIX域套接字服務器和客戶端未雙向通信

[英]UNIX domain socket server and client not communicating bi-directionally

我寫了一個C ++服務器和一個PHP客戶端,它們都基於UNIX域套接字進行通信。 雙向閱讀或書寫都可以。 一旦嘗試讀取然后寫入(反之亦然),通訊就不會結束:客戶端在一段時間后返回“ 504網關超時”,服務器在打印“等待身份驗證...”后一直保持等待狀態。 ”。

PHP客戶端:

<?php
$sock = socket_create(AF_UNIX, SOCK_STREAM, 0);
$conn = socket_connect($sock, '/tmp/some.socket');


$pass = "pass\0";

if ($sock == FALSE)
    echo "Error: <br />   $errstr ($errno)<br />\n";
else
{
    echo "Sending the password... ";

    $ret = socket_write($sock, $pass, strlen($pass));

    if ($ret == FALSE)
        echo "error! " .  socket_strerror( socket_last_error());
    else
    {
        echo "Password was sent.<br /> ";

        $auth = socket_read($sock, 256);

        if (FALSE === $auth) 
            echo "sending password failed; reason: " . socket_strerror(socket_last_error($sock)) . "\n";
        else if ($auth != "authenticated")
            echo "Authentication failed: $auth.";
        else
            echo "Authentication was successful. <br />";
    }
}

socket_close($sock);

?>

主服務器cpp文件:

#include <iostream>

#include "UnixDomainSocket.hpp"


int main()
{
    try
    {
        UnixDomainSocket uds("/tmp/some.socket");

        std::cout << "Server started." << std::endl;

        while (true)
        {
            //if a new connection stablished, read and process data 
            if (uds.newConnectionEstablished())
            {
                std::cout << "Got a new connection. Waiting for authentication..." << std::endl;

                std::string command = uds.getClientMsg().getValue();

                if (command != "pass")
                {
                    std::cout << "401" << std::endl;
                    uds.sendMsg("401");
                }
                else
                {
                    std::cout << "authenticated" << std::endl;

                    auto msgRet = uds.sendMsg("authenticated");
                }

                uds.closeConnection();
            }
        }
    }
    catch (const std::string & err)
    {
        std::cout << "Error: " << err << std::endl;

        return -1;
    }
    catch (const std::exception & err)
    {
        std::cout << "Error: " << std::string(err.what()) << std::endl;

        return -1;
    }
    catch (...)
    {
        std::cout << "Unhandled error occured. Daemon stopped." << std::endl;

        return -1;
    }
    std::cout << "Server shut down." << std::endl;
}

服務器頭:

#ifndef UNIXDOMAINSOCKET_HPP
#define UNIXDOMAINSOCKET_HPP

#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>

#include <string>

#include "Expected.hpp"


const int BUFFSIZE = 1024;

class UnixDomainSocket
{
public:
    UnixDomainSocket (const std::string & socketPath);
    ~UnixDomainSocket();

    bool newConnectionEstablished();
    Expected<std::string> getClientMsg();
    Expected<bool> sendMsg (const std::string & msg);
    void closeConnection();
    void closeConnection (const std::string & quitMessage);

protected:
    std::string socketPath;
    unsigned long maxConnections;
    bool connectionEstablished;

    struct sockaddr_un addr;
    int serverFileDescriptor, clientFileDescriptor;
    ssize_t bytes;
    char buf[BUFFSIZE];
};

#endif

服務器cpp:

#include "UnixDomainSocket.hpp"

#include <iostream>


UnixDomainSocket::UnixDomainSocket (const std::string & socketPath)
    : socketPath(socketPath), maxConnections(100)
{
    if ((serverFileDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
        throw "socket  error";

    memset (&addr, 0, sizeof(addr));

    //ensure that all fields, including non−standard ones, are initialized to 0
    addr.sun_family = AF_UNIX;

    //we copy one byte less, ensuring a trailing 0 exists
    strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);


    if (access(addr.sun_path, F_OK) == 0)
        unlink(addr.sun_path);

    if (bind(serverFileDescriptor, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
        throw "bind error";

    if (listen(serverFileDescriptor, maxConnections) < 0)
        throw "listen error";
}

UnixDomainSocket::~UnixDomainSocket()
{
    closeConnection();
}

bool UnixDomainSocket::newConnectionEstablished()
{
    if ((clientFileDescriptor = accept(serverFileDescriptor, NULL, NULL)) < 0)
         throw "accept error";

     connectionEstablished = true;

     return true;
}

Expected<std::string> UnixDomainSocket::getClientMsg()
{
    if (!connectionEstablished)
        return Expected<std::string>::fromException(std::logic_error("No connection established yet."));

    std::string msg;

    while ((bytes = read (clientFileDescriptor, buf, BUFFSIZE)) > 0)
        msg += buf;

    // if (msg.length())
    //     throw "empty msg from client";

    if (bytes < 0)
        throw "read error";

    return msg;
}

Expected<bool> UnixDomainSocket::sendMsg (const std::string & msg)
{
    if (!connectionEstablished)
        return Expected<bool>::fromException(std::logic_error("No connection established yet."));

    if (msg.empty())
        return Expected<bool>::fromException(std::logic_error("The message must be not empty."));


    auto bytesSent = send(clientFileDescriptor, (msg + "\n").c_str(), msg.length(), MSG_CONFIRM);

    ////Also tried:
    // long bytesSent = -1;
    // while (bytesSent < 0)
    //     bytesSent = write(clientFileDescriptor, msg.c_str(), msg.length());

    if (bytesSent != msg.length())
        return Expected<bool>::fromException(std::logic_error("Error occured while sending."));

    return true;
}


void UnixDomainSocket::closeConnection (const std::string & quitMessage)
{
    sendMsg(quitMessage);
    closeConnection();
}

void UnixDomainSocket::closeConnection()
{
    if (close(clientFileDescriptor) < 0)
        throw "close error";

    connectionEstablished = false;
}

問題是您的實施

getClientMsg() {
...
while ((bytes = read (clientFileDescriptor, buf, BUFFSIZE)) > 0)
    msg += buf;
...

其中,該功能(再次)在

read()

一旦成功通過了“ pass”。 因此,在while循環中,您需要檢查每個邊界

send()

我對您的代碼做了一些修改,現在可以找到它:

while ((bytes = read (clientFileDescriptor, buf, BUFFSIZE)) > 0)
{
    msg += buf;

    if (buf[bytes] == 127) break; // completion of one send()
}

服務器截圖

客戶端截圖

我注意到的另一件事是,您在主循環的每次迭代結束時都關閉了套接字:

uds.closeConnection();

這將禁用以后之間的通信。 因此,最好刪除此行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM