?
Du machst mich grad wütend.
Wenn du meine Posts nicht verstanden hast, dann sagt das direkt, und versuche nicht, etwas ausprobieren, was meine Posts bereits beschreiben, und frag nicht, warum die Implementierung, die die von mir beschriebenen Fallen beinhaltet, nicht funktioniert.
while(1)
{
printf("Enter message : ");
scanf("%s" , message);
//Receive a reply from the server
/*Falsch, falsch, falsch. Sagte ich nicht bereits, dass du dich nicht darauf
**verlassen kannst, dass dir recv direkt die komplette Nachricht gibt? Wieso
**ignorierst du das?*/
//if( recv(sock , server_reply , 2000 , 0) < 0)
//{
// puts("recv failed");
// break;
//}
}
Noch einmal:
dachschaden schrieb:
Du musst prüfen, wann du denkst, dass nicht mehr eingeladen werden muss. Ein recv zu viel, und dein Programm blockiert. Einer zu wenig, und du hast nicht genug Daten. recv kann dir einmal ein komplettes LV-Paket geben, und dann wieder nur ein Teil dieses Paketes.
Da, da hast du es. Hier steht exakt dein Problem. Du prüfst nicht, ob deiner Meinung nach die Nachricht vollständig ist, du gehst davon aus, dass "das schon so passen wird". Nein. Tut es nicht. Nicht unbedingt zumindest. Deswegen musst du nach dem recv die Prüfung machen, ob das so in Ordnung ist.
Hier mal ein Beispiel - kannst du so nicht anwenden, weil ich halt das Protokoll nicht kenne, aber es sollte dir eine Idee geben (schamlos aus einem meiner älteren Projekte geklaut):
#define CLEAR_RESPONSE (*response_length)=0;free((*response))
do
{
/*Timeouthandling*/
mtv=(*tv);
readfds=savefds;
select(max_socket,&readfds,0,0,&mtv);
if(!FD_ISSET(socket,&readfds))
{
/*OK, über Timeout, damit sind wir RAUS.*/
CLEAR_RESPONSE;
return ETIMEDOUT;
}
/*Prüfen, ob wir genug Speicher haben - damit langweile ich dich jetzt
**nicht, da stehen genug Abstraktionen hinter.*/
/*Dann endlich lesen. Wie ich bereits sagte, wenn select sagt, dass sich
**was am Socket getan hat, aber keine Daten eingelesen werden konnten, wenn
**ich sie erwarte, ist das ein Fehler. Ob in der Protokollprüfung oder bei
**der Gegenseite, das ist mir egal.*/
if((cur_pack_length=recv(socket,(*response)[*response_length],max_reserved_bytes-(*response_length),0))<1)
{
CLEAR_RESPONSE;
return ECONNRESET;
}
/*Merken, dass sich unser Response vergrößert hat.*/
(*response_length)+=cur_pack_length;
/*Jetzt wird es interessant, die Protokollprüfung.
**Wir haben im Grunde drei Stadien: 1. Alles in Ordnung, der Response ist
**so gültig. 2. Sieht bisher ganz gut aus, aber da fehlt noch was - mach noch
**weiter recv, bis ich "Stop" sage. 3. Habe hier Müll bekommen, kann ich
**nicht verarbeiten, muss weg.
**
**Ich verwende hier einen Funktionspointer, damit die Funktion, die diese
**Funktion aufruft, ihr eigenes Protokoll verwenden kann. Sie muss nur sagen, wann
**genug ist und wann nur Blödsinn vorliegt. current_protocol_state ist eine Helfer-
**Variable für Spezialfälle wie HTTP, weil man hier nicht ständig nach \r\n und
**\r\n\r\n suchen muss, wenn man diese Information schon längst hat.*/
enum PROTOCOL_STATUS current_result=check(request,(*response),(*response_length),current_protocol_state);
/*Komplett untauglich.*/
if(current_result==PROTOCOL_STATUS_FAILED)
{
CLEAR_RESPONSE;
return EPROTO;
}
}
/*Tja - und die Funktion macht dann halt so lang weiter, bis
**PROTOCOL_STATUS_OK zurückkommt.*/
while(current_result==PROTOCOL_STATUS_CONTINUE);
Der check kann dann so aussehen wie bei SOCKS:
enum PROTOCOL_STATUS socks4_check
(
UNUSED_PARAMETER(const char*request),
UNUSED_PARAMETER(const char*response_so_far),
const size_t response_length,
UNUSED_PARAMETER(USES_PERSISTENT_STATE)
)
{
/*Für SOCKS4 müssen wir glücklicherweise nur die Länge prüfen.*/
if(response_length<8)
return PROTOCOL_STATUS_CONTINUE;
else if(response_length==8)
return PROTOCOL_STATUS_OK;
else
return PROTOCOL_STATUS_FAILED;
}