2012-05-16 7 views
0

Я разрабатываю сервер в C, используя сокеты bsd, в которых я получаю jpeg-фреймы от клиентов.Как записать данные байта из сокета в неподписанный символ char в C?

Данные кадра поступают на сервер как поток байтовых данных формата jpeg.

Поскольку эквивалент байта - это символ без знака в C, я получаю эти данные в unsigned char vector над несколькими итерациями функции sock.recv().

Проблема в том, что когда я пишу эти данные в файл .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; 
} 

да я получать данные на сервере правильно, как я также создал сервер dunmmy в Питоне и реконструированы кадры там успешно , Вот что я делаю в 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() 
+3

Можете ли вы разместить часть кода, который вы используете? Наиболее полезной будет часть, записывающая код в файл. –

+0

Просто выстрел в темноте: вы закрываете выходной файл правильно? – m0skit0

+1

Вы переписываете и не добавляете в свой файловый буфер. –

ответ

1

recv() возвращает размер полученных данных.

поэтому вы можете получить размер файла с возвращаемого значения recv().

Если вы получили размер файла (4 байта), от recv() возвращаемое значение, возможно, что-то не так с данными передачи (socket).

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); 
0

Основываясь на том, что вы сказали, до сих пор, это выглядит, как ваш код, который ISN» т есть что-то вроде этого (я не компилятор, так что могут быть некоторые ошибки синтаксиса):

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); 

В противном случае evertime вы идете вокруг петли, вы начинаете еще в начале буфера (buffer[0]), а не в первый пустой слот в буфере (buffer[i]).

Ваш цикл for работает только в том случае, если в соке есть buffersize или более байтов. Если изображение должно состоять из нескольких фреймов (один из которых был небольшим), или изображение должно быть меньше кадра, я ожидаю, что ваш метод прекратит возвращать -1. Это действительно то, что вы хотите делать? Я бы предположил, что, возможно, это:

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

должно быть что-то вроде:

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

Таким образом, до тех пор, как вы что-то из сокета чтения вы возвращаете его, что позволяет за короткий промежуток , Но это действительно зависит от вашего приложения, это просто что-то, что нужно запомнить.

Вы не можете использовать cout << buffer.data() для вывода двоичной информации, считанной из сокета, поскольку предполагается, что вход завершен с нулевым значением. Вы можете записать двоичные данные с помощью cout.write((const char*)buffer.data(), bufferContentSize), однако не забудьте, что это приведет к записи двоичных данных на вашу консоль (что может означать, что все они видны и могут иметь различные другие воздействия, в зависимости от вашей консоли, поскольку они интерпретируют управляющие символы).