0

例如,假设我需要通过套接字将五个图像从客户端发送到服务器,并且我想立即执行此操作(而不是发送一个并等待 ACK)。

问题:

  1. 我想知道是否有一些最佳实践或指导方针来界定每个人的结尾。

  2. 在服务器中检测分隔符和处理每个图像的最安全方法是什么?(如果可能,使用C/C++

提前致谢!

4

3 回答 3

1

由于图像是二进制数据,因此很难想出不能包含在图像中的分隔符。(最终使接收方感到困惑)

我建议您创建一个标题,该标题将放置在传输的开头或每个图像的开头。

一个例子:

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

发件人应在每张图片之前添加此内容并正确填写长度。然后,接收者将知道图像何时结束,并期望在该位置有另一个 Header 结构。

属性(打包)是一种安全性,即使您使用不同的 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 回答