Pergunta

Estou construindo um programa de servidor-cliente com C e tendo alguma problen wtih sendina um arquivo inteiro com a função send () e recv (). Preciso enviar o arquivo inteiro com isso, mas todas essas funções podem fazer é enviar uma string. O principal problema é o envio do exe ou outros dados binários de formato. Devo usar htons ou htonl func? Não sei como usá -los ao longo deles, pois sou apenas um noob.

Estou preso a isso e adoro sua ajuda. Obrigado!!

Aqui está a função RECV do lado do servidor ::

if (socket_type != SOCK_DGRAM)
    {

            fi = fopen (final,"wb");
            retval = recv(msgsock, recv_buf, strlen(recv_buf), 0);
            /*recv_buf[retval] = '\0';
            fprintf (fi,"%s",recv_buf);*/

            int i;
            i=atoi(recv_buf);
            char *q;
            q=(char *)malloc(i*sizeof(char));
            retval = recv(msgsock, q, strlen(q), 0);
            //printf ("%s",q);
            fwrite(q,i,1,fi);
            fclose(fi);

    }
    else
    {
        retval = recvfrom(msgsock,recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from, &fromlen);
        printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
        printf ("SOCK_DGRAM");
    }

    if (retval == SOCKET_ERROR)
    {
        fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
        closesocket(msgsock);
        //continue;
    }
    else
        printf("Server: recv() is OK.\n");

    if (retval == 0)
    {
        printf("Server: Client closed connection.\n");
        closesocket(msgsock);
            //continue;
    }
    printf("Server: Received %d bytes, data from client\n", retval);

O lado do cliente envia função :::

void send_Command () {int bytesent; Arquivo *file_out; // file_out = fopen (file_path, "rb"); char str_all [100000]; // sinalizador [30] = "end";

///////////////////////getsize//////////////
char fsize[5];
int filesize;
file_out = fopen(file_path, "rb");
fseek(file_out, 0, SEEK_END);
filesize = ftell(file_out);
rewind (file_out);
itoa (filesize,fsize,10);
/////////////////////////////////////////////
send (ConnectSocket, fsize, strlen (fsize), 0);

char *r = (char *)malloc (filesize * sizeof(char));

fread(r,filesize,1,file_out);
bytesent = send( ConnectSocket, r, strlen(r), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
fclose (file_out);

/*while (fscanf(file_out,"%s",&str_all) != EOF)
{
    bytesent = send( ConnectSocket, str_all, strlen(str_all), 0 );
    printf("\nClient: Bytes sent: %ld\n", bytesent);
    //Sleep(500);
}*/

/*printf("%s",flag);
send( ConnectSocket, flag, strlen(flag), 0 );*/
WSACleanup();
//return 0;
}
Foi útil?

Solução

Você precisará implementar essa funcionalidade ou usar uma biblioteca que o faça. send(2) Apenas envia um buffer de byte cru. Se você quiser enviar um arquivo, precisará usar algum tipo de protocolo que o cliente e o servidor entendem.

O protocolo mais simples possível pode ser que o cliente envie o nome do arquivo, o comprimento do arquivo e, em seguida, os dados do arquivo bruto. Por exemplo (verificação de erros omitida para maior clareza):

// Server:
const char *filename = ...;
uint32_t filenameLen = strlen(filename);
uint32_t filenameLenNet = htonl(filenameLen);
send(fd, &filenameLenNet, sizeof(filenameLenNet), 0);
send(fd, filename, filenameLen, 0);

// You should probably use a 64-bit file length; also, for large files, you
// don't want to read the entire file into memory, you should just stream it
// from disk to network in reasonably-sized chunks.
const void *fileData = ...;
uint32_t fileLen = ...;
uint32_t fileLenNet = htonl(fileLen);
send(fd, &fileLenNet, sizeof(fileLenNet), 0);
send(fd, fileData, fileLen, 0);

// Client:
char *filename;
uint32_t filenameLen;
recv(fd, &filenameLen, sizeof(filenameLen), 0);
filenameLen = ntohl(filenameLen);
filename = malloc(filenameLen + 1);
recv(fd, filename, filenameLen, 0);
filename[filenameLen] = 0;
uint32_t fileLen;
recv(fd, &fileLen, sizeof(fileLen), 0);
fileLen = ntohl(fileLen);
void *fileData = malloc(fileLen);
recv(fd, fileData, fileLen, 0);
// Write file Data to the output file.  Again, for large files, it would be
// better to stream it in in chunks instead of reading it all in at once.

Além disso, tenha cuidado com o envio/recebimento parcial. Verifique os valores de retorno de send e recv, pois eles podem (e fazer) geralmente enviar ou receber apenas um subconjunto dos dados que você pretende enviar ou receber. Quando isso acontece, você deve se recuperar resistente ou recepando em um loop até que você processe todos os dados que pretendia ou ocorra um erro.

Como alternativa ao uso de seu próprio protocolo, você pode usar um protocolo existente com uma biblioteca como libftp ou libcurl.

Outras dicas

Send () não envia uma string, ele envia uma matriz de bytes. Você cria seu buffer, preenche -o, envia o buffer e passa o número de bytes para enviar () e a partir daí.

Dependendo do sistema operacional em que você está, pode haver um sendfile comando; Mas não é garantido que funcione portavelmente em diferentes sistemas operacionais. A maneira mais portátil é apenas read() o arquivo em pedaços em um buffer e depois write() isso fora (ou send() fora, se você está usando um soquete, embora write() deve funcionar bem também).

Ver Minha resposta para esta pergunta anterior perguntando essencialmente a mesma coisa.

O que você precisa fazer é enviar seus dados em vários pedaços, um pedaço de cada vez. Então, essencialmente, você lê seu arquivo n bytes de cada vez em um buffer e envia () esses n bytes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top