unix stream sockets de domínio de enviar mais dados, então deve ser
Pergunta
Eu tenho dois programas simples configurar que compartilham dados através de um soquete do domínio Unix. Um programa lê os dados a partir de uma fila e envia-lo para o outro aplicativo. Antes de ser enviado a cada parte de dados é anexada-frente por quatro bytes com o comprimento, se ele for inferior a quatro bytes os bytes são deixados sobre o símbolo '^'.
A aplicação do cliente, em seguida, lê os primeiros quatro bytes, define um buffer para o tamanho apropriado e, em seguida, lê o resto. O problema que estou tendo é que pela primeira vez através da mensagem será enviada perfeitamente. Todas as outras vezes depois que há dados extra sendo enviado assim que uma mensagem do tipo "o que é um bom dia para fora" sairia como "o que é um bom dia para fora ?? X ??". Então, eu me sinto como um buffer não está sendo limpo corretamente, mas eu não consigo encontrá-lo.
O código do cliente:
listen(sock, 5);
for (;;)
{
msgsock = accept(sock, 0, 0);
if (msgsock == -1)
perror("accept");
else do
{
char buf[4];
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 4)) < 0)
perror("reading stream message");
printf("--!%s\n", buf);
string temp = buf;
int pos = temp.find("^");
if(pos != string::npos)
{
temp = temp.substr(0, pos);
}
int sizeOfString = atoi(temp.c_str());
cout << "TEMP STRING: " << temp << endl;
cout << "LENGTH " << sizeOfString << endl;
char feedWord[sizeOfString];
bzero(feedWord, sizeof(feedWord));
if ((rval = read(msgsock, feedWord, sizeOfString)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", feedWord);
bzero(feedWord, sizeof(feedWord));
sizeOfString = 0;
temp.clear();
}
while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
Código Servidor
pthread_mutex_lock(&mylock);
string s;
s.clear();
s = dataQueue.front();
dataQueue.pop();
pthread_mutex_unlock(&mylock);
int sizeOfString = strlen(s.c_str());
char sizeofStringBuffer[10];
sprintf(sizeofStringBuffer, "%i", sizeOfString);
string actualString = sizeofStringBuffer;
int tempSize = strlen(sizeofStringBuffer);
int remainder = 4 - tempSize;
int x;
for(x =0; x < remainder; x++)
{
actualString = actualString + "^";
}
cout << "LENGTH OF ACTUAL STRING: " << sizeOfString << endl;
actualString = actualString + s;
cout << "************************" << actualString << endl;
int length = strlen(actualString.c_str());
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
if (write(sock, finalString, length) < 0)
perror("writing on stream socket");
Solução
Ao invés de prencher o seu tamanho do pacote com '^
', você estaria muito melhor apenas fazendo:
snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString);
para que o valor é 0 acolchoado -. Então você não precisa analisar os caracteres '^' no código receptor
Por favor, também editar o seu código de depuração -. Só há uma write()
no código atual, e isso não corresponde à sua descrição do protocolo
O ideal - dividir sua rotina de envio em uma função própria. Você também pode tirar proveito de writev()
a alça coalescentes a corda segurando o campo "tamanho" com o tampão que contém os dados reais e, em seguida, enviá-los como um único write()
atômica.
código não testado seguinte:
int write_message(int s, std::string msg)
{
struct iovec iov[2];
char hdr[5];
char *cmsg = msg.c_str();
int len = msg.length();
snprintf(hdr, 5, "%04d", len); // nb: assumes len <= 9999;
iov[0].iov_base = hdr;
iov[0].iov_len = 4;
iov[1].iov_base = cmsg;
iov[1].iov_len = len;
return writev(s, iov, 2);
}
Outras dicas
Você tem que verificar valores de retorno de ambos write
e read
não só para -1
mas para curto (menos solicitado) escreve / lê. Você também parecem apenas continuar depois de imprimir um erro com perror
-. Fazer uma exit(2)
ou algo lá
Duas coisas:
Primeiro -. No lado do servidor que você está escrevendo para fora da extremidade do seu array
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
O strcpy()
irá copiar personagens length+1
em finalString
(personagem puxar o terminador nulo).
Em segundo lugar (e mais provável que seja o problema) - no lado do cliente que não são nulos encerra o string que você ler, portanto, o printf()
irá imprimir sua seqüência, e então tudo o que está na pilha até o ponto que atinge um nulo.
Aumentar ambos os buffers por um, e você deve estar em melhor forma.