0

クライアントからjpegフレームを受信して​​いるbsdソケットを使用してCでサーバーを開発しています。

フレームデータは、jpeg形式のバイトデータのストリームとしてサーバーに到着します。

Cでは同等のバイトはunsignedcharであるため、sock.recv()関数を数回繰り返して、このデータをunsignedcharベクトルに受け取ります。

問題は、このデータを.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()
4

3 に答える 3

1

recv()受信データのサイズを返します。

の戻り値からファイルサイズを取得できますrecv()

戻り値からファイルサイズ(4バイト)を取得した場合recv()、転送データに問題がある可能性があります(socket)。

于 2012-05-16T03:43:38.183 に答える
0

あなたがこれまでに言ったことに基づいて、あなたのコードは次のように見えます (私はコンパイラを持っていないので、構文エラーがあるかもしれません):

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]

for ループはbuffersize、ソケットから読み取るバイトが 1 つ以上ある場合にのみ機能します。画像が複数のフレーム (そのうちの 1 つが小さい) で構成されている場合、または画像がフレームよりも小さい場合、メソッドが を返すことを中止することが期待されます-1。これは本当にあなたがやりたいことですか?おそらくこれをお勧めします:

if (nChars <= 0) {
    return -1;
}   

次のようにする必要があります。

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

そうすれば、ソケットから何かを読み取っている限り、それを返すことができるため、短いフレームが可能になります。しかし、これは本当にあなたのアプリケーションに依存します。

cout << buffer.data()入力が null で終了していると見なされるため、ソケットから読み取ったバイナリ情報を出力するために使用することはできません。を使用してバイナリ データを書き込むことができますが、cout.write((const char*)buffer.data(), bufferContentSize)そうするとバイナリ データがコンソールに書き込まれることに注意してください (制御文字を解釈するコンソールによっては、すべてが表示され、その他のさまざまな影響が生じる可能性があります)。

于 2012-05-16T10:07:29.177 に答える
0

暗闇での完全な突き刺し。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);
于 2012-05-16T04:16:46.030 に答える