发送文件时套接字写入失败

时间:2013-12-04 20:21:11

标签: c++ image file sockets buffer

我一直坚持这个问题,因为我无法通过套接字发送文件。我使用这种方法发送了其他信息,但是当我尝试将PNG文件作为字符串发送时,似乎出现了问题。

这些是我用来发送和接收信息的方法:

// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message)
{
    // Write the Message Size to the Socket
    send(socket, itoa((message.length() + 1)), sizeof(size_t));

    // Wait for Write Confirmation
    bool response;
    receive(socket, &response, 2);

    // Write the Message to the Socket
    send(socket, (char*) message.c_str(), message.length() + 1);

    // Wait for Write Confirmation
    receive(socket, &response, 2);
}

// Receives Message from the specified Socket
string Server::receiveMessage(int socket)
{
    // Read the Message Size from the Socket
    int size;
    receive(socket, &size, sizeof(size_t));

    // Send Write Confirmation
    send(socket, itoa(true), 2);

    // Receive the Message from the Socket
    char message[size];
    receive(socket, message, size);

    // Send Write Confirmation
    send(socket, itoa(true), 2);

    // Return the Message as a String
    string msg(message);
    return msg;
}

发送接收方法只是分别用于写入读取的中继。我只是在这些方法中进行错误检查,而发送方法告诉我无法正常工作。如果重要,这是我的发送方法:

// Sends a Data Packet to the specified Socket
int Server::send(int socket, void* data, int size)
{
    // Write the Data to the Socket
    int count = write(socket, data, size);

    // Make sure the Write Succeeded
    if(count == -1)
    {
            print("$f1Error: $f0Unable to Write to Socket $t1%i$t0\n", socket);
            exit(1);
    }

    return count;
}

我应该注意服务器作为线程运行,因此上述三个函数是静态的。客户端还包含相同的四个网络功能。

打破这种情况的命令行发生在我用来处理客户端的单独的静态函数中。以下是所述方法的相关部分:

// Handles each Client with a Thread 
void* Server::server_handleClient(void* arg)
{
    // Determine the Socket Descriptor
    int socket = *((int*) arg);
    free(arg);

    // Create the Rover
    Rover* rover = new Rover();

    // Loop Indefinitely
    while(true)
    {
        ...
        // Take a Picture and Send it
        sendMessage(socket, rover -> takePicture());
        ...
    }

    // Delete the Rover
    delete rover;

    // Close the Socket
    close(socket);

    // Return a Successful Status
    return (void*) new int(0);
}

在这里你可以看到我使用了我创建的另一个类的方法。以下是流动站类中的 takePicture 方法,这是我实际抓住图片的地方:

// Takes a Picture and Returns the Photo as a String
inline string Rover::takePicture()
{
    // Open the Picture File
    ifstream picture;
    string filepath = "./Server/Pictures/" + getDirection() + ".png";
    picture.open(filepath.c_str());

    // Make sure the File Opened
    if(!picture.is_open())
            return "";

    // Read the File into a String Buffer
    stringstream buffer;
    buffer << picture.rdbuf();

    return buffer.str();
}

简而言之,服务器会从流动站中获取一张照片,然后将其发送到客户端。当我检查照片的字符串内容时,它就在那里。所有可能的照片大小合适(用于测试的照片为674,962字节,发送的缓冲区大小为674,963)

我已经使用这些方法发送各种消息,所有这些都很好。我能够发送字符串(比如“Hello World!”)和整数就好了。

有什么我做错了吗?我试图发送的文件太大了吗?是否有一些我缺少的信息?我需要帮助......


修改 我做了一些改进,取得了一些进展。我对 sendMessage 命令做了一个小改动。目前的问题是图片没有正确发送。

sendMessage 功能:

// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message, bool data = false)
{
        // Write the Message Size to the Socket
        send(socket, itoa((message.length() + 1)), sizeof(size_t));

        // Wait for Write Confirmation
        bool response;
        receive(socket, &response, 2);

        // Determine the Type of Data to Send
        if(data)
        {
                // Write the Message Data to the Socket
                send(socket, (char*) message.data(), message.length() + 1);
        }
        else
        {
                // Write the Message to the Socket
                send(socket, (char*) message.c_str(), message.length() + 1);
        }

        // Wait for Write Confirmation
        receive(socket, &response, 2);
}

客户的此功能副本已更新为匹配。

现在我们正在努力保存PNG文件,这里也是处理这个问题的函数:

// Handles each Client with a Thread 
void* Client::client_handleServer(void* arg)
{
        // Define Socket Variables
        int socket = *((int*) arg);
        free(arg);

        ...
        // Export the Picture to the Client's Directory
        message = receiveMessage(socket);
        ofstream picture;
        picture.open("./Client/Pictures/Picture.png", std::ifstream::binary);
        picture << message;
        picture.close();
        ...
}

3 个答案:

答案 0 :(得分:1)

目前您正在使用textmode打开文件。这意味着文件中包含换行符“\ n”的任何字符都将转换为换行符+回车符“\ r \ n”。

以二进制模式打开文件,如此

picture.open(filepath.c_str(), std::ifstream::binary);

然后它可能会起作用。

答案 1 :(得分:1)

void Server::sendMessage(int socket, string message)

问题就在这里。不要将string用作二进制数据的容器。将图像作为字节数组传递。同样适用于此:

string Server::receiveMessage(int socket)

答案 2 :(得分:0)

从长远来看,我最终想出了一切。

图片是二进制文件,我使用的是使用ASCII字符的字符串。这个问题是二进制数据并不总是转换为ASCII,而字符串由空字符终止,而二进制数据可以包含空数据。长话短说,字符串不起作用。

为了保留我已经存在的消息处理,我最终只是将二进制数据转换为十六进制数据(0-F),可以用字符串显示。