TOP
SSV Software Systems Register  Register
Log in to check your private messages  Log in to check your private messages
Startseite FAQ Search Mitglieder Profile  Log in 
SSV Support-Forum
TCP, Datendurchsatz beim Senden von DNP stark eingeschränkt

 
Post new topic   Reply to topic    SSV-Forum Forum Index >>> DNP/5280
<<< Previous topic - Next topic >>>  
Display posts from previous:   
Author Message
gierd



Joined: 29 Jun 2007
Posts: 3
Location: Celle

PostPosted: 29.06.2007, 09:51    Post subject: TCP, Datendurchsatz beim Senden von DNP stark eingeschränkt Reply with quote

Hallo Forum,

für eine DNP/5280 (uCLinux Rev. 3) habe ich eine Programm geschrieben, dass Daten über TCP an einen Client senden soll. Dabei stellte ich fest, dass nicht alle Daten ankommen, sondern ein paar immer wieder verloren gehen. Manche messages kommen einfach nicht beim Client an. Für die Analyse der Ursache des Problems habe ich eine Client-Server-Anwendung geschrieben, die auf den Quellen von pont basiert. 15 Telegramme mit je 12 byte habe ich direkt hintereinander von der DNP zu einem PC geschickt, über Port 5000. In der Hälfte der Fälle kommen nicht alleTelegramme an. Dieselbe Software zum Senden der Pakete habe ich auf einer älteren Version der DNP (uCLinux Rev. 2) installiert, und dort kommen 90 % aller Pakete auch beim Empfänger an. Wenn ich nach jedem 12-Byte Paket eine Wartezeit von 120 us einbaue, kommen bei beiden DNP's alle Pakete an. Kann mir Jemand einen Tipp geben, wie ich dafür sorgen kann, dass auch ohne Verzögerung alle Pakete beim Empfänger ankommen ?

Nachfolgend die Quellen. Der Client läuft auf der DNP, der Server wartet auf dem PC auf ankommende Daten.

Nachfolgend der C-Code vom Server. Die Anzahl der insgesamt angekommenen Pakete wird am Ende der Ausführung angezeigt.
---------------------------------------------
// tcpServer.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>

#define SUCCESS 0
#define ERROR 1

#define END_LINE 0x0
#define SERVER_PORT 5000
#define MAX_MSG 6145

int counter; // for counting the total amount of messages

int read_line();

int main (int argc, char *argv[]) {

int sd, newSd, cliLen;

struct sockaddr_in cliAddr, servAddr;
char line[MAX_MSG];
counter = 0;

/* create socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd<0)
{
perror("cannot open socket ");
return ERROR;
}

/* bind server port */
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(SERVER_PORT);

if(bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr))<0)
{
perror("cannot bind port ");
return ERROR;
}

listen(sd,20);

while(1)
{
printf("%s: waiting for data on port TCP %u\n",argv[0],SERVER_PORT);

cliLen = sizeof(cliAddr);
newSd = accept(sd, (struct sockaddr *) &cliAddr, &cliLen);
if(newSd<0)
{
perror("cannot accept connection ");
return ERROR;
}

/* init line */
memset(line,0x0,MAX_MSG);

/* receive segments */
while(read_line(newSd,line)!=ERROR)
{
ntohs(cliAddr.sin_port);
inet_ntoa(cliAddr.sin_addr);

/* init line */
memset(line,0x0,MAX_MSG);

}
}
}

int read_line(int newSd, char *line_to_return)
{
static int rcv_ptr=0;
static char rcv_msg[MAX_MSG];
int i = 0;

int n;
int offset;

offset=0;

while(1)
{
if(rcv_ptr==0)
{
/* read data from socket */
memset(rcv_msg,0x0,MAX_MSG); /* init buffer */
n = recv(newSd, rcv_msg, MAX_MSG, 0); /* wait for data */

if(n>0)
{
for(i=0;i<n;i++)
printf("Byte %d: %X\n",i, rcv_msg[i]);
counter = counter + n;
printf("Total: %d messages, Received new messages: %d\n\n",counter, n);
}
else if (n < 0)
{
perror(" cannot receive data ");
return ERROR;
}
else if (n==0)
{
printf(" connection closed by client\n");
close(newSd);
return ERROR;
}
}

/* copy line into 'line_to_return' */
while(*(rcv_msg+rcv_ptr)!=END_LINE && rcv_ptr<n)
{
memcpy(line_to_return+offset,rcv_msg+rcv_ptr,1);
offset++;
rcv_ptr++;
}

/* end of line + end of buffer => return line */
if(rcv_ptr==n-1)
{
/* set last byte to END_LINE */
*(line_to_return+offset)=END_LINE;
rcv_ptr=0;
return ++offset;
}

/* end of line but still some data in buffer => return line */
if(rcv_ptr < n-1)
{
/* set last byte to END_LINE */
*(line_to_return+offset)=END_LINE;
rcv_ptr++;
return ++offset;
}

/* end of buffer but line is not ended => */
/* wait for more data to arrive on socket */
if(rcv_ptr == n)
{
rcv_ptr = 0;
}

}
}
--------------------------------------------------------------
Nun der Cient, welcher auf der DNP gesetartet wird und einmal 15 Pakete mit insgesamt 180 byte sendet.
--------------------------------------------------------------
// tcpClient.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>

#define SERVER_PORT 5000
#define MAX_MSG 6145

int main (int argc, char *argv[])
{
int j = 0;
int sd, rc, i=0;

struct sockaddr_in localAddr, servAddr;
struct hostent *h;

if(argc < 3)
{
printf("usage: %s <server> <data1> <data2> ... <dataN>\n",argv[0]);
exit(1);
}

h = gethostbyname(argv[1]);
if(h==NULL)
{
printf("%s: unknown host '%s'\n",argv[0],argv[1]);
exit(1);
}

servAddr.sin_family = h->h_addrtype;
memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servAddr.sin_port = htons(SERVER_PORT);

/* create socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd<0)
{
perror("cannot open socket ");
exit(1);
}

/* bind any port number */
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = htons(0);
rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
if(rc<0)
{
printf("%s: cannot bind port TCP %u\n",argv[0],SERVER_PORT);
perror("error ");
exit(1);
}

/* connect to server */
rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
if(rc<0)
{
perror("cannot connect ");
exit(1);
}

while(j < 15)
{
rc = send(sd, argv[i], strlen(argv[i]) + 1, 0);

if(rc < 0)
{
perror("cannot send data ");
close(sd);
exit(1);
}
else
{
printf("%d: %s: data %u sent (%s)\n", j, argv[0],i-1,argv[i]);
j++;
}
// usleep(120); // delay as work-around
}
return 0;
}
--------------------------------------------------------
Gesartet wird der Client mit:
./tcpClient IP-Adresse_vom_PC z
Wobei z für einen Buchstaben steht, der als solcher zum Server gesendet wird.
Würde mich sehr freuen wenn mir Jemand einen Tipp geben könnte, wie ich den Paketverlust ohne Verzögerung vermeiden kann ?

Mit freundlichen Grüßen und vielen Dank im Vorraus,

Dennis Gier
Back to top
View user's profile Send private message
kdw



Joined: 05 May 2006
Posts: 1460

PostPosted: 02.07.2007, 08:14    Post subject: Datenverlust mit TCP … Reply with quote

Hallo.

Wenn man mit einer TCP-Verbindung Daten verliert, macht man einen konzeptionellen Fehler. Auf der Protokollebene ist jedenfalls durch die TCP-Eigenschaften sichergestellt, dass alle Daten beim Empfänger in der richtigen Reihenfolge ankommen.

Die Schwachstelle ist erfahrungsgemäß die Empfängerseite. Dort müssen die eingehenden Daten zunächst zwischengespeichert werden. Dafür sind Datenpuffer erforderlich. Wenn die nicht ausreichend groß sind, können aus der Sicht des auslesenden Prozesses Daten verloren gehen. Dann müssen die Daten schnell genug abgeholt werden.

Beim Senden besonders kleiner Datenpakete ist weiterhin zu beachten, dass auf Grund der Ethernet-Eigenschaften (minimale Blockgröße, MTU, usw.) immer auf die minimal erforderliche Länge aufgefüllt werden.

Ansonsten empfiehlt sich er Einsatz eines Ethernet Sniffers (Ethereal, Wireshark o.ä.), um die Verbindung zu Debuggen (wann geht was verloren????).

Gruß

KDW

P.S.: Der LAN-Datendurchsatz des DNP/528x ist in der Tat nicht sehr hoch. Die Ursachen sind u.a. die Probleme des ColdFire-MAC. Siehe hierzu auch http://www.dilnetpc.com/MCF5282DE.pdf (Punkte 9. und 10.).
Back to top
View user's profile Send private message
kdw



Joined: 05 May 2006
Posts: 1460

PostPosted: 02.07.2007, 08:43    Post subject: Es gehen Daten verloren … Reply with quote

Hallo.

Mir ist da noch etwas aufgefallen: Bzgl. der printf-Anweisungen im Client-Code, würde ich hinter jede Ausgabeanweisung ein

fflush(stdout);

setzen. Printf ist bekanntlich eine gepufferte Ausgabe. Man kann daher nicht erwarten, dass jedes printf im Quellcode bei der Ausführung auch sofort eine Ausgabe verursacht. Evtl. geht ja garnichts verloren, es werden nur nicht alle printf ausgegeben.

Gruß

KDW
Back to top
View user's profile Send private message
gierd



Joined: 29 Jun 2007
Posts: 3
Location: Celle

PostPosted: 02.07.2007, 14:37    Post subject: Ethernet-Problem Reply with quote

Hallo KDW,

viele Dank schonmal für die Antworten. Das Problem tritt jedoch nicht beim Client auf, sondern beim Server (= PC), welcher die Daten empfängt, die der Client (= DNP 5280) sendet. Beim Server lasse ich einen Zähler mitlaufen dessen Wert am Ende als "Total"-Wert augegeben wird., Er zeigt unabhängig von evtl verlorenen printf's, dass in vielen Fällen nicht alle 180 gesendeten bytes ankommen. Der Buffer i m Server ist eigentlich auch groß genug dimensioniert (6145), der in der Funktion readline als Größe für das Buffer-Array gewählt und als zweiter Parameter im recv() angewendet wird.
Ich werde mal Ethereal mitlaufen lassen, melde mich dann nochmal.

Grüße,

Dennis
Back to top
View user's profile Send private message
gierd



Joined: 29 Jun 2007
Posts: 3
Location: Celle

PostPosted: 03.07.2007, 12:52    Post subject: Konnte Verlust zeigen Reply with quote

Hallo Forum und KDW,

nachdem ich Ethereal beim Senden von 180 byte gleichzeitig laufen ließ, wurde deutlich dass von 15 gesendeten, 12-byte-großen Paketen lediglich 12 Pakete wirklich nur gesendet wurden. Ob hier das Ethernet-Defizit des Coldfire-Prozessors zum Tragen kommt ?
Werde weiter graben.

Beste Grüße,

Dennis Gier
Back to top
View user's profile Send private message
kdw



Joined: 05 May 2006
Posts: 1460

PostPosted: 04.07.2007, 13:42    Post subject: Nur 12 von 15 Paketen wurden wirklich gesendet ... Reply with quote

Hallo.

Ich gehe davon aus, dass die Ursache im Softwarebereich zu suchen ist. Das Problem des ColdFire dürfte hier nicht der Verursacher sein.

Ich würde zunächst einmal folgendes klären:

1. Was ändert sich, wenn der Aufruf der send()-Funktion mit deutlich längeren Sendedaten erfolgt (zum Beispiel Strings mit 16 oder mehr Bytes Länge)?

2. Wer leitet den Abbau der TCP-Verbindung lt. Ethereal in die Wege? Der Server oder der Client?

Gruß

KDW
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    SSV-Forum Forum Index >>> DNP/5280 All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

SSV Software Systems GmbH

Dünenweg 5
30419 Hannover

Fon: +49(0)511  ·  40 000-0
Fax: +49(0)511  ·  40 000-40

sales@ssv-embedded.de


Impressum    ·    Datenschutz    ·    AGB

© 2023 SSV SOFTWARE SYSTEMS GmbH. Alle Rechte vorbehalten.

ISO 9001:2015