如何将字节数据从套接字写入 C 中的无符号字符向量? [关闭]

Posted

技术标签:

【中文标题】如何将字节数据从套接字写入 C 中的无符号字符向量? [关闭]【英文标题】:How to write byte data from socket into an unsigned char vector in C? [closed] 【发布时间】:2012-05-16 03:11:19 【问题描述】:

我正在使用 bsd 套接字在 C 中开发一个服务器,我在其中接收来自客户端的 jpeg 帧。

帧数据作为jpeg格式的字节数据流到达服务器。

由于字节等价物在 C 中是 unsigned char,因此我通过 sock.recv() 函数的多次迭代将这些数据接收到 unsigned char 向量中。

问题是当我将此数据写入 .jpg 文件时,文件大小仅显示为 4 个字节。

我还检查了在帧的所有迭代中从 recv 缓冲区中挑选的字节数等于发送帧的总大小,但不知何故,它们没有正确写入我使用的向量中。

有人知道怎么做吗?谢谢 !

这是我从套接字读取数据的代码:

int Socket::readFrame(vector<unsigned char> &buffer,int buffsize)
MyLog Log;
buffer.resize(buffsize);
int nChars;
int readlen;
fd_set fset;            
struct timeval tv;      
int sockStatus;
FD_ZERO(&fset);
FD_SET(socketHandle, &fset);
tv.tv_sec = 0;
tv.tv_usec = 50;
sockStatus = select(socketHandle + 1, &fset, NULL,&fset, &tv);      
if (sockStatus <= 0) 
    return sockStatus;


int i;
for(i=0;i<buffsize;i+=nChars)
    cout<<"I="<<i<<endl;
    //Log.v("Reading");
    FD_ZERO(&fset);
    FD_SET(socketHandle, &fset);
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    sockStatus = select(socketHandle + 1, &fset, NULL,&fset, &tv);
    if (sockStatus < 0) 
        return -1;
    
    nChars = ::recv(socketHandle, &buffer[0] , buffsize-i, MSG_NOSIGNAL);
    cout<<nChars<<endl;
    if (nChars <= 0) 
        return -1;
    


    cout<<buffer.data();
    return i;

是的,我在服务器上正确接收数据,因为我还在 PYTHON 中创建了一个虚拟服务器并成功地重建了那里的帧。这是我在 python 中所做的:

import socket,thread
import string
import array
host="172.16.82.217"
port=54321
s=socket.socket()
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host,port))
s.listen(5)
conn,address=s.accept()
if conn:
    print "accepted"
totalLength=""
for i in range(0,10):
    data=""
    mylen=0
    dataRecv=0
    file1 = open("myfile%d.jpg"%i,"w")
    length=conn.recv(1024)
    print length
    conn.send("recvd\n")
    mylen=int(length)

    while dataRecv<mylen:
        newData=""
        newData=conn.recv(1)
        if not newData:
            break
        data+=newData
        dataRecv+=len(newData)

    file1.write(data)
    file1.close()
    print len(data)
conn.close()
s.close()

【问题讨论】:

你能发布一些你正在使用的代码吗?将代码写入文件的部分将是最有用的。 只是在黑暗中拍摄:您是否正确关闭了输出文件? 您正在覆盖而不是附加到您的文件缓冲区。 已经添加了上面的代码!请检查并查看。 这个nChars = ::recv(socketHandle, &amp;buffer[0] , buffsize-i, MSG_NOSIGNAL); 总是写入缓冲区的开头,这是故意的吗?你是如何写入文件的? 【参考方案1】:

recv() 返回接收数据的大小。

所以,你可以从recv()的返回值中获取文件大小。

如果从recv()返回值得到文件大小(4字节),可能是传输数据有问题(socket)。

【讨论】:

【参考方案2】:

在黑暗中完全刺伤。您是否使用 sizeof 来确定要写入的字节数并在指针上使用 sizeof:

unsigned char *data = ...
write(fd, data, sizeof(data));

如果这是您的问题,sizeof 只是返回指针本身使用的字节数。由于这是二进制数据,因此您需要跟踪从 recv 获得的字节数并使用它:

size_t total_bytes = 0;
...
ssize_t bytes = recv(...);
if (bytes != -1)
  total_bytes += bytes;
....
write(fd, data, total_bytes);

【讨论】:

【参考方案3】:

根据你到目前为止所说的,看起来你的代码不存在这样的东西(我没有编译器,所以可能存在一些语法错误):

ofstream out;
out.open("SOMEFILE.jpg", ios::out | ios::binary);

while(moreFrames) 
    int bytesRead = clientsocket.readFrame(buffer, frameSize);
    out.write(reinterpret_cast<char*>(buffer.data()), bytesRead);

    // some check to see if there are more frames.


out.close();

一些注意事项。您是否以二进制模式打开 jpeg 文件?您是否将正确的大小写入文件?您是否只在开始时打开文件+在最后一帧之后关闭它(而不是为每一帧打开/写入/关闭?)

对于您发布的代码,似乎有几个问题需要考虑。这个:

nChars = ::recv(socketHandle, &buffer[0] , buffsize-i, MSG_NOSIGNAL); 

应该是这样的

nChars = ::recv(socketHandle, &buffer[i] , buffsize-i, MSG_NOSIGNAL);

否则,每当您绕过循环时,您都会从缓冲区的开头 (buffer[0]) 开始,而不是缓冲区中的第一个空槽 (buffer[i])。

只有在有buffersize 或更多字节要从套接字读取时,您的 for 循环才有效。如果图像由多个帧组成(其中一个很小),或者图像小于一个帧,我希望您的方法中止返回-1。这真的是你想做的吗?我建议也许这样:

if (nChars <= 0) 
    return -1;
   

应该是这样的:

if (nChars <= 0) 
    if (i <= 0) 
        return -1;
    
    break;

这样,只要您从套接字中读取了某些内容,您就会返回它,从而允许短帧。但这实际上取决于您的应用程序,这只是要牢记在心的事情。

您不能使用cout &lt;&lt; buffer.data() 来输出从套接字读取的二进制信息,因为它会假定输入为空终止。您可以使用cout.write((const char*)buffer.data(), bufferContentSize) 写入二进制数据,但请记住,这样做会将二进制数据写入您的控制台(可能会注意到所有数据都是可见的,并且可能会产生各种其他影响,具体取决于您的控制台在解释控制字符时)。

【讨论】:

以上是关于如何将字节数据从套接字写入 C 中的无符号字符向量? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Java 中的无符号字节中获取浮点数?

正确类型转换字节以写入 C++ 中的串行句柄

C中的无符号字符连接

如何从无符号变量中写入和读取字节

C#编组来自C++ DLL的无符号字符返回值[重复]

C中的无符号整数在java中的处理