0

たとえば、ソケットを介してクライアントからサーバーに 5 つの画像を送信する必要があり、一度に送信したいとします (1 つを送信して ACK を待つのではなく)。

質問:

  1. それぞれの終わりを区切るためのベスト プラクティスやガイドラインがあるかどうかを知りたいです。

  2. サーバーで区切り文字を検出し、各画像を一度処理するための最も安全な方法は何ですか? (可能であればC/C++で)

前もって感謝します!

4

3 に答える 3

1

画像はバイナリデータなので、画像に収まらない区切り文字を考え出すのは難しいでしょう。(そして最終的に受信側を混乱させる)

送信の最初、または各画像の最初に配置されるヘッダーを作成することをお勧めします。

例:

struct Header
{
    uint32_t ImageLength;
//  char ImageName[128];
} __attribute__(packed);

送信者は、各画像の前にこれを追加し、長さを正しく入力する必要があります。受信者は、画像がいつ終了するかを認識し、その位置で別のヘッダー構造を期待します。

属性(packed)は安全であり、異なる GCC バージョンでサーバーとクライアントをコンパイルした場合でも、ヘッダーが同じ配置になるようにします。構造が異なるプロセスによって解釈される場合に推奨されます。

データ ストリーム: ヘッダー画像データ ヘッダー画像データ ヘッダー画像データ ...

于 2013-09-03T08:32:33.927 に答える
1

これらの関数を使用して、(Java のクライアントから) サーバー (C の) にファイルを送信できます。ファイルのサイズを示す 4 バイトを送信し、その後にファイルの内容を送信します。すべてのファイルが送信されたら、転送の終了を示すために 4 バイト (すべて 0 に設定) を送信します。

// Compile with Microsoft Visual Studio 2008

// path, if not empty, must be ended with a path separator '/'
// for example: "C:/MyImages/"
int receiveFiles(SOCKET sck, const char *pathDir)
{
    int fd;
    long fSize=0;
    char buffer[8 * 1024];
    char filename[MAX_PATH];
    int count=0;

    // keep on receiving until we get the appropiate signal 
    // or the socket has an error
    while (true)
    {
        if (recv(sck, buffer, 4, 0) != 4)
        {
            // socket is closed or has an error
            // return what we've received so far
            return count; 
        }
        fSize = (int) ((buffer[0] & 0xff) << 24) |
                (int) ((buffer[1] & 0xff) << 16) |
                (int) ((buffer[2] & 0xff) <<  8) |
                (int)  (buffer[3] & 0xff);
        if (fSize == 0) 
        {
            // received final signal
            return count; 
        }
        sprintf(filename, "%sIMAGE_%d.img", pathDir, count+1);
        fd = _creat(filename, _S_IREAD | _S_IWRITE);
        int iReads;
        int iRet;
        int iLeft=fSize;
        while (iLeft > 0)
        {
            if (iLeft > sizeof(buffer)) iReads = sizeof(buffer);
            else iReads=iLeft;
            if ((iRet=recv(sck, buffer, iReads, 0)) <= 0)
            {
                _close(fd);
                // you may delete the file or leave it to inspect
                // _unlink(filename); 
                return count; // socket is closed or has an error
            }
            iLeft-=iRet;
            _write(fd, buffer, iRet);
        }
        count++;
        _close(fd);
    }
}

クライアント部分

/**
 * Send a file to a connected socket.
 * <p>
 * First it send the file size if 4 bytes then the file's content.
 * </p>
 * <p>
 * Note: File size is limited to a 32bit signed integer, 2GB
 * </p>
 * 
 * @param os
 *           OutputStream of the connected socket
 * @param fileName
 *           The complete file's path of the image to send
 * @throws Exception
 * @see {@link receiveFile} for an example on how to receive the file from the other side.
 * 
 */
public void sendFile(OutputStream os, String fileName) throws Exception
{
    // File to send
    File myFile = new File(fileName);
    int fSize = (int) myFile.length();
    if (fSize == 0) return; // No empty files
    if (fSize < myFile.length())
    {
        System.out.println("File is too big'");
        throw new IOException("File is too big.");
    }

    // Send the file's size
    byte[] bSize = new byte[4];
    bSize[0] = (byte) ((fSize & 0xff000000) >> 24);
    bSize[1] = (byte) ((fSize & 0x00ff0000) >> 16);
    bSize[2] = (byte) ((fSize & 0x0000ff00) >> 8);
    bSize[3] = (byte) (fSize & 0x000000ff);
    // 4 bytes containing the file size
    os.write(bSize, 0, 4);

    // In case of memory limitations set this to false
    boolean noMemoryLimitation = true;

    FileInputStream fis = new FileInputStream(myFile);
    BufferedInputStream bis = new BufferedInputStream(fis);
    try
    {
        if (noMemoryLimitation)
        {
            // Use to send the whole file in one chunk
            byte[] outBuffer = new byte[fSize];
            int bRead = bis.read(outBuffer, 0, outBuffer.length);
            os.write(outBuffer, 0, bRead);
        }
        else
        {
            // Use to send in a small buffer, several chunks
            int bRead = 0;
            byte[] outBuffer = new byte[8 * 1024];
            while ((bRead = bis.read(outBuffer, 0, outBuffer.length)) > 0)
            {
                os.write(outBuffer, 0, bRead);
            }
        }
        os.flush();
    }
    finally
    {
        bis.close();
    }
}

クライアントからファイルを送信するには:

try
{
    // The file name must be a fully qualified path
    sendFile(mySocket.getOutputStream(), "C:/MyImages/orange.png");
    sendFile(mySocket.getOutputStream(), "C:/MyImages/lemmon.png");
    sendFile(mySocket.getOutputStream(), "C:/MyImages/apple.png");
    sendFile(mySocket.getOutputStream(), "C:/MyImages/papaya.png");
    // send the end of the transmition
    byte[] buff = new byte[4];
    buff[0]=0x00;
    buff[1]=0x00;
    buff[2]=0x00;
    buff[3]=0x00;
    mySocket.getOutputStream().write(buff, 0, 4);

}
catch (Exception e)
{
    e.printStackTrace();
}
于 2013-09-03T18:48:51.130 に答える
0

長さを含むヘッダーを簡単に送信できない場合は、可能性のある区切り文字を使用してください。画像が圧縮されておらず、ビットマップタイプのデータで構成されている場合、完全に飽和した輝度値は通常まれであるため、おそらく 0xFF/0XFFFF/0xFFFFFFF でしょうか?

エスケープ シーケンスを使用して、データ内で現れる区切り文字のインスタンスをすべて排除します。

これは、両端ですべてのデータを反復することを意味しますが、データフローととにかく行われていることによっては、便利な解決策になる可能性があります:(

于 2013-09-03T08:43:45.140 に答える