Entwickler-Ecke

Internet / Netzwerk - Winsock: recv


Peter18 - Mi 01.04.15 17:11
Titel: Winsock: recv
Ein freundliches Hallo an alle,

nach dem Client und Server endlich miteinander reden, würder ich gern verstehen worüber sie reden.

Mit recv habe ich anscheinend wieder ein Problem mit Pointern. MS sagt:

C#-Quelltext
1:
2:
3:
4:
5:
6:
int recv(
  _In_   SOCKET s,
  _Out_  char *buf,
  _In_   int len,
  _In_   int flags
);

Also "_Out" ist ein Pointer. In der "winsock.pas" steht folgendes:


Delphi-Quelltext
1:
function recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;                    


Delphi-Quelltext
1:
2:
3:
4:
var
  recvbuf    : array [1..512of Char;
...
Res := recv( CSock, recvbuf, recvbuflen, 0 );
liefert mir aber nicht den Text.
Offenbar steht dort der Pointer auf den String. Pascal und Pointer mein Lieblingsthema! Kann mir jemand sagen was da falsch ist?
AllocMem zuweisen??

Grüße von der Nordsee

Peter


Sinspin - Mi 01.04.15 18:30

Hallo Peter,

ich würde einiges anders machen Anstatt:

Delphi-Quelltext
1:
2:
3:
4:
var
  recvbuf    : array [1..512of Char;
...
Res := recv( CSock, recvbuf, recvbuflen, 0 );

würde ich:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
const
  BuffSize = 2048// 2K

var
  recvbuf : array [0..BuffSize-1of Byte; // falls du mal auf ein neueres Delphi umsteigst wird dir das einige Sucherrei ersparen.
...
Res := recv( CSock, recvbuf, BuffSize, 0 );

nehmen.

- Den Puffer legt man selber an, das hast Du also richtig gemacht.
- Char hat in neueren Versionen mehr als ein Byte. Also lieber Byte anstelle von Char verwenden.
- Ein etwas größerer Puffer reduziert die Anzahl der itereationen die Du brauchst bis keine Daten mehr kommen. (falls eines deiner Datenpakete mal etwas größer werden sollte).
- Ist Res > 0 wurden Daten geliefert die dann im Puffer stehen.
- Ob die Funktion ohne Daten zurückkehren kann oder nicht liegt am Typ des Sockets, wenn ja wird Res = 0 geliefert falls keine Daten im internen Puffer von Windows waren.
- wenn Res = -1 (SOCKET_ERROR) ist musst Du WSAGetLastError verwenden um herauszufinden was klemmt.

Ich rate dringend dazu Dir alles zum Thema Recv in der MSDN durchzulesen. Eventuell sind die Beispiele dort auch hilfreich.
Eventuell solltest du nach einer neueren Version der winsock.pas im Netz suchen in der auch neuere Funktionen definiert sind. Delphi 4 ist ja jetzt doch schon etwas älter.

Grüße von angenehm warmen persischen Golf.


Peter18 - Mi 01.04.15 18:55

Hallo Stefan,

Danke für Deine Antwort. Heute komme ich nicht mehr dazu den Tipp auszuprobieren, werde mich morgen daransetzen und berichten. Die Puffergröße ist noch kein Problem, zum testen reist es und für mein Vorhaben warscheinlich auch, aber trotzdem Dank auch für diesen Tipp.
Die Remarks habe ich anscheinend Übersehen, weil sie so weit unten sind.

Grüße von der Nordsee an den persischen Golf. Da fehlt dann nur noch etwas klares Wasser und Steilküste.

Peter


Peter18 - Do 02.04.15 11:17

Hallo Stefan,

leider sieht das Ergebnis nicht sehr viel besser aus. Ich bekomme noch immer Hyroglyphen als Ergebnis (siehe Anhang). Mit den Pointern ist noch etwas faul. Wie gesagt Pascal und Pointer, mein Lieblingsthema.

Grüße von der verschneiten Mordsee

Peter


baumina - Do 02.04.15 11:40

Irgendwie würde ich sagen, dass recvbuf ein PChar oder PByte sein sollte.

EDIT:
Folgende Funktion hab ich in inet gefunden, evtl. passts ja bei dir auch:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Var
   Buffer : String;
   R : Integer;
begin
   SetLength(Buffer,1024);
   R:=recv(S_accepting, buffer[1], Length(buffer),0);
   If (R < 0Then --fehler--

   SetLength(Buffer,R); // Empfangene Daten stehen nun im Buffer (String)
   OutputDebugString(PChar(Buffer)); // Sichtbar im Eventlog - Ctrl-Alt-V
end;


Peter18 - Do 02.04.15 12:41

Hallo baumina,

Dank für Deine Antwort, aber ich erhalte noch immer irgend etwas, aber nicht den gesendeten Text sondern "Text: øm“" oder ähnliches.

Vielleicht liegt der Fehler ja auch beim Sender.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.Button2Click(Sender: TObject);      // Senden
var
  Res : Integer;
  Buf : PChar;

begin
  Memo1.Lines.Add( 'Sende: ' + Edit3.Text );
  Buf := PChar( Edit3.Text );
  Res := send( CSock, Buf, Length( Edit3.Text ), 0 );
  if Res = SOCKET_ERROR then
  begin
    Memo1.Lines.Add( 'Fehler beim Senden.' );
  end;
end;

Der Server sagt zwar er hat die entsprechende Anzahl Zeichen empfangen, aber das sagt ja noch nicht welche.

Grüße von der sonnigen Nordsee

Peter


Peter18 - Do 02.04.15 13:40

Ein freundliches Hallo an alle,

ein Debug auf Assemblerebene hat gezeigt das beim Senden der String kopiert, also vermutlich korrekt behandelt und gesendet wird. Der Server jedoch liefert mit konstanter Bosheit zwar die richtige Anzaahl Zeichen, sonst aber nur Zeichensalat.

Grüße von der Nordsee

Peter


Nersgatt - Do 02.04.15 13:55

Das ist ein Thema, mit dem ich mich auch immer schwer tue. Aber müsste es nicht
Res := recv( CSock, @recvbuf[1], recvbuflen, 0 );
heißen? Einfach mal probieren.

Grüße aus der schmuddeligen Grafschaft Bentheim. :D


Peter18 - Do 02.04.15 14:20

Hallo Jens,

Dank für Deine Antwort. Ich fürchte das wird nicht funktionieren, weil es dann ein Pointer ist. In der Winsock.pas ist es aber als "var" deklariert.

Ich kann es aber noch nicht testen, weil bei der herumspielerei jetzt nichts mehr gesendet wird. Melde mich sobald das behoben und Dein Vorschlag getestet ist.


Grüße von der wieder sonnigen Nordsee

Peter


Sinspin - Do 02.04.15 14:56

Ich habe ein bisschen gekoggelt und eine andere Version der winsock.pas gefunden in der der Parameter als PChar angegeben ist.
Eigentlich sollte es auch mit deiner Version gehen. Ich schließe mich diesbezüglich user profile iconNersgatt ein bisschen an, lasse aber das @ weg und beginne, wie in meinem Beispiel deklariert, mit Position 0 des Arrays.

Delphi-Quelltext
1:
Res := recv( CSock, recvbuf[0], BuffSize, 0 );                    

Grüße vom persichen Golf, nach Durchzug des krassesten Sandsturms den ich jeh gesehen habe.


Peter18 - Do 02.04.15 18:56

Hallo Jens,

wie Erwartet hat der Compiler gemeckert.

Hallo Stefan,

auch Dein Vorschlag hat nicht geklappt.

Die Probleme, die ich zwischendurch hatte, lagen nicht am Client sondern am Server. Ich hatte dass Array mit 0 gefüllt. Delphi handhabt Strings anscheinend über eine Pointerkette. Denn das Array wurde, wie ich vermute, als Nil-Pointer betrachtet und daher wurden keine Daten zurückgegeben.

Die Preisfrage ist, wie muß ein Konstrukt aussehen, das bei Delphi funktioniert?


Delphi-Quelltext
1:
2:
Type recvbuff  = PChar;
Type Precvbuff = ^recvbuff;

Das reicht nicht, denn es ist Nil.

Werde erst mal in dieser Richtung morgen weiterforschen. Tipps sind nach wie vor willkommen!

Grüße von der noch immer sonnigen (nanu) Nordsee

Peter


Peter18 - Do 02.04.15 19:34

Ein freundliches Hallo an alle,

inzwischen kann ich das bestätigen: PChar ist ein Pointer der auf einen Pointer zeigt. Der wiederum zeigt auf den String.

Grüße von der immer noch sonnigen Nordsee

Peter


jaenicke - Do 02.04.15 21:34

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
inzwischen kann ich das bestätigen: PChar ist ein Pointer der auf einen Pointer zeigt. Der wiederum zeigt auf den String.
Ein PChar ist ein Pointer auf ein Zeichen, ggf. gefolgt von mehreren weiteren Zeichen im Speicher. Am Ende steht ein Nullzeichen.
Das ist kein doppelter Pointer.


Peter18 - Fr 03.04.15 15:37

Hallo Sebastian,

kann sein, dass Du recht hast. Eindeutige Ergebnisse habe ich noch nicht. Das ich mich einige male auf der Suche nach meinem String verlaufen habe scheint daran zu liegen, dass der Pointer auch gern mal in einem Register landet und nicht in der Variablen gespeichert wird (Optimierung). Der Pointer in der Variablen zeigt dann irgendwo hin und es war warscheinlich ein Zufall, dass ich über die Kette auf den String gestoßen bin.

Mein Problem mit dem Server ist anscheinend die Parameterübergabe. Ich habe einen Bereich mit blanks durch eine Pointervariable übergeben. Manchmal stand dort ein Wert wie ein Pointer oder der Speicher war unverändert. Werde weiter forschen :x , aber hoffe jemand kan mir sagen wie die Übergabe richtig funktioniert.

Grüße von der Sonnigen und nicht mehr so windigen Nordsee

Peter


Delete - Fr 03.04.15 23:32

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Mein Problem mit dem Server ist anscheinend die Parameterübergabe.


Dein Problem könnte auch dein Halbwissen sein, so von wegen doppelter Pointer: ein Pchar ist ein Pointer, der auf einen Pointer zeigt. :lol:


Peter18 - Sa 04.04.15 12:06

Hallo Perlsau,

wenn hier jemand mit gefählichem Halbwissen unterwegs ist dann ja wohl Du!! Wer nicht einmal weiß, dass Systemschnittstellen nur per CPU-Debug untersucht werden können, sollte keine solchen Sprüche machen.

Wenn Du hilfreiche Beiträge hast sind die willkommen! Wenn Du weiter nur dumme Sprüche auf Lager hast muß ich Deine Beiträge wohl nochmals melden.


jaenicke - Sa 04.04.15 12:24

Kannst du das aktuelle Projekt vielleicht einmal anhängen? Vielleicht lässt sich dann eher etwas sagen...


Peter18 - Sa 04.04.15 13:26

Hallo Sebastian,

selbstverständlich! Genügt die Unit oder auch die "winsock.pas" und die Projektdatei?

Hier erst mal die Unit:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
unit Srv;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Winsock, Winsock2, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Memo1: TMemo;
    Edit2: TEdit;
    Label2: TLabel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private-Deklarationen}
  public
    { Public-Deklarationen}
  end;

var
  Form1     : TForm1;
  Connected : Boolean = False;
  CSock     : TSocket = INVALID_SOCKET;
  SSock     : TSocket = INVALID_SOCKET;

implementation

{$R *.DFM}

Const
  DEFAULT_BUFLEN = Integer( 512 );

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Enabled  := False;
  Timer1.Interval := 1000;
end;

procedure TForm1.Button1Click(Sender: TObject);      // Verbinden
var
  VerR    : word;
  WSADATA : TWSAData;
  Res     : Integer;
  hints   : PAddrInfo;
  ARes    : PAddrInfo;

begin
  VerR := 2;
  Res := WSAStartup( VerR, WSADATA );       //  10092 = WSAVERNOTSUPPORTED
  if Res = 0 then
  begin
    hints             := AllocMem( SizeOf( TAddrInfo ) );
    hints.ai_flags    := 0;
    hints.ai_family   := AF_INET;     // Internetprotokoll
    hints.ai_socktype := SOCK_STREAM;
    hints.ai_protocol := IPPROTO_TCP;
    hints.ai_flags    := AI_PASSIVE;

    // Resolve the server address and port
    Res := getaddrinfo(Nil, PChar( Edit2.Text ), hints, ARes );
    if Res = 0 then
    begin
      // Create a SOCKET for connecting to server
      SSock := socket( ARes.ai_family, ARes.ai_socktype, ARes.ai_protocol );
      if SSock <> INVALID_SOCKET then
      begin
        // Setup the TCP listening socket
        Memo1.Lines.Add( 'socket' );
        Res := bind( SSock, ARes.ai_addr^, ARes.ai_addrlen );
        if Res <> SOCKET_ERROR then
        begin
          freeaddrinfo( ARes );
          Memo1.Lines.Add( 'listen' );
          Res := listen( SSock, SOMAXCONN );
          if Res = 0 then
          begin
            // Accept a client socket
            Memo1.Lines.Add( 'accept' );
            CSock := accept( SSock, NilNil );
            Memo1.Lines.Add( 'Accept: ' + IntToStr( CSock ) );
            if CSock <> INVALID_SOCKET then
            begin
              // No longer need server socket
              closesocket( SSock );
              // Receive until the peer shuts down the connection

            end
            else
            begin
              Memo1.Lines.Add( 'Fehler Erstellen des Clientports: ' + IntToStr( WSAGetLastError ) );
              closesocket( SSock );
              WSACleanup;
            end;
          end
          else  // listen ServerSock
          begin
            Memo1.Lines.Add( 'Fehler Portprüfung: ' + IntToStr( WSAGetLastError ) );
            closesocket( SSock );
            WSACleanup;
          end;
        end
        else  // bind
        begin
          Memo1.Lines.Add( 'Fehler beim Binden: ' + IntToStr( WSAGetLastError ) );
          freeaddrinfo( ARes );
          closesocket( SSock );
          WSACleanup;
        end;
      end
      else    // socket
      begin
        Memo1.Lines.Add( 'Fehler beim Erstellen des Socket : ' + IntToStr( WSAGetLastError ) );
        freeaddrinfo( ARes );
        WSACleanup;
      end;
    end
    else      // getaddrinfo
    begin
      Memo1.Lines.Add( 'Fehler bei der Portprüfung: ' + IntToStr( Res ) );
      WSACleanup;
    end;
  end
  else        // WSAStartup
  begin
    Memo1.Lines.Add( 'Initialisierungsfehler: ' + IntToStr( Res ) );
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);      // Trennen
begin
  if CSock <> INVALID_SOCKET then
  begin
    closesocket( CSock );
    WSACleanup;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);      // Listen
begin
  Timer1.Enabled := Not Timer1.Enabled;
  if Timer1.Enabled then Memo1.Lines.Add( 'Timer gestartet.'  )
                    else Memo1.Lines.Add( 'Timer angehalten.' );
end;

procedure TForm1.Timer1Timer(Sender: TObject);
const
  BuffSize = 2048// 2K

Type recvbuff  = PChar;    
Type Precvbuff = ^recvbuff;

var
  Res        : Integer;
  Buffer  : String;
  recvbuf    : Pointer;
  PSt        : PChar;
  I          : Integer;
  S          : WideString;

begin
  recvbuf  := AllocMem( BuffSize );
  PSt := 'abcdefg';
  Res        := recv( CSock, recvbuf, BuffSize, 0 );   
  if Res >= 0 then
  begin
    Memo1.Lines.Add( IntToStr( Res ) + ' Zeichen empfangen.' );
    Buffer := String( recvbuf );
    Memo1.Lines.Add( 'Text: ' + Buffer );  
    Memo1.Lines.Add( 'Sende: ' + PSt );
    Res := send( CSock, PSt, MSG_DONTROUTE, 0 ); 
    if Res = SOCKET_ERROR then
    begin
      Memo1.Lines.Add( 'Fehler beim Senden: ' + IntToStr( WSAGetLastError ) );
      closesocket( CSock );
      WSACleanup;
    end;
  end
  else
  begin
    Timer1.Enabled := false;;               // Noch genauer prüfen
    Memo1.Lines.Add( 'Abbruch durch Klient: ' + IntToStr( WSAGetLastError ) );
    closesocket( CSock );
    WSACleanup;
  end;

end;

end.

Wie schon erwähnt, alles Quick and dirty, aber es geht mir zunächst darum den Einstieg zu finden und dann wird das, was ich brauche in einem Objekt verpackt.

Hier noch die "Winsock2.pas", die Ergänzungen zur Winsock enthält.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
unit Winsock2;

interface

uses winsock;

const
  WSABASEERR = 10000;
  {$EXTERNALSYM WSABASEERR}

//
// Windows Sockets definitions of regular Microsoft C error constants
//

  WSAEINTR  = WSABASEERR + 4;
  {$EXTERNALSYM WSAEINTR}
  WSAEBADF  = WSABASEERR + 9;
  {$EXTERNALSYM WSAEBADF}
  WSAEACCES = WSABASEERR + 13;
  {$EXTERNALSYM WSAEACCES}
  WSAEFAULT = WSABASEERR + 14;
  {$EXTERNALSYM WSAEFAULT}
  WSAEINVAL = WSABASEERR + 22;
  {$EXTERNALSYM WSAEINVAL}
  WSAEMFILE = WSABASEERR + 24;
  {$EXTERNALSYM WSAEMFILE}

//
// Windows Sockets definitions of regular Berkeley error constants
//

  WSAEWOULDBLOCK     = WSABASEERR + 35;
  {$EXTERNALSYM WSAEWOULDBLOCK}
  WSAEINPROGRESS     = WSABASEERR + 36;
  {$EXTERNALSYM WSAEINPROGRESS}
  WSAEALREADY        = WSABASEERR + 37;
  {$EXTERNALSYM WSAEALREADY}
  WSAENOTSOCK        = WSABASEERR + 38;
  {$EXTERNALSYM WSAENOTSOCK}
  WSAEDESTADDRREQ    = WSABASEERR + 39;
  {$EXTERNALSYM WSAEDESTADDRREQ}
  WSAEMSGSIZE        = WSABASEERR + 40;
  {$EXTERNALSYM WSAEMSGSIZE}
  WSAEPROTOTYPE      = WSABASEERR + 41;
  {$EXTERNALSYM WSAEPROTOTYPE}
  WSAENOPROTOOPT     = WSABASEERR + 42;
  {$EXTERNALSYM WSAENOPROTOOPT}
  WSAEPROTONOSUPPORT = WSABASEERR + 43;
  {$EXTERNALSYM WSAEPROTONOSUPPORT}
  WSAESOCKTNOSUPPORT = WSABASEERR + 44;
  {$EXTERNALSYM WSAESOCKTNOSUPPORT}
  WSAEOPNOTSUPP      = WSABASEERR + 45;
  {$EXTERNALSYM WSAEOPNOTSUPP}
  WSAEPFNOSUPPORT    = WSABASEERR + 46;
  {$EXTERNALSYM WSAEPFNOSUPPORT}
  WSAEAFNOSUPPORT    = WSABASEERR + 47;
  {$EXTERNALSYM WSAEAFNOSUPPORT}
  WSAEADDRINUSE      = WSABASEERR + 48;
  {$EXTERNALSYM WSAEADDRINUSE}
  WSAEADDRNOTAVAIL   = WSABASEERR + 49;
  {$EXTERNALSYM WSAEADDRNOTAVAIL}
  WSAENETDOWN        = WSABASEERR + 50;
  {$EXTERNALSYM WSAENETDOWN}
  WSAENETUNREACH     = WSABASEERR + 51;
  {$EXTERNALSYM WSAENETUNREACH}
  WSAENETRESET       = WSABASEERR + 52;
  {$EXTERNALSYM WSAENETRESET}
  WSAECONNABORTED    = WSABASEERR + 53;
  {$EXTERNALSYM WSAECONNABORTED}
  WSAECONNRESET      = WSABASEERR + 54;
  {$EXTERNALSYM WSAECONNRESET}
  WSAENOBUFS         = WSABASEERR + 55;
  {$EXTERNALSYM WSAENOBUFS}
  WSAEISCONN         = WSABASEERR + 56;
  {$EXTERNALSYM WSAEISCONN}
  WSAENOTCONN        = WSABASEERR + 57;
  {$EXTERNALSYM WSAENOTCONN}
  WSAESHUTDOWN       = WSABASEERR + 58;
  {$EXTERNALSYM WSAESHUTDOWN}
  WSAETOOMANYREFS    = WSABASEERR + 59;
  {$EXTERNALSYM WSAETOOMANYREFS}
  WSAETIMEDOUT       = WSABASEERR + 60;
  {$EXTERNALSYM WSAETIMEDOUT}
  WSAECONNREFUSED    = WSABASEERR + 61;
  {$EXTERNALSYM WSAECONNREFUSED}
  WSAELOOP           = WSABASEERR + 62;
  {$EXTERNALSYM WSAELOOP}
  WSAENAMETOOLONG    = WSABASEERR + 63;
  {$EXTERNALSYM WSAENAMETOOLONG}
  WSAEHOSTDOWN       = WSABASEERR + 64;
  {$EXTERNALSYM WSAEHOSTDOWN}
  WSAEHOSTUNREACH    = WSABASEERR + 65;
  {$EXTERNALSYM WSAEHOSTUNREACH}
  WSAENOTEMPTY       = WSABASEERR + 66;
  {$EXTERNALSYM WSAENOTEMPTY}
  WSAEPROCLIM        = WSABASEERR + 67;
  {$EXTERNALSYM WSAEPROCLIM}
  WSAEUSERS          = WSABASEERR + 68;
  {$EXTERNALSYM WSAEUSERS}
  WSAEDQUOT          = WSABASEERR + 69;
  {$EXTERNALSYM WSAEDQUOT}
  WSAESTALE          = WSABASEERR + 70;
  {$EXTERNALSYM WSAESTALE}
  WSAEREMOTE         = WSABASEERR + 71;
  {$EXTERNALSYM WSAEREMOTE}

//
// Extended Windows Sockets error constant definitions
//

  WSASYSNOTREADY         = WSABASEERR + 91;
  {$EXTERNALSYM WSASYSNOTREADY}
  WSAVERNOTSUPPORTED     = WSABASEERR + 92;
  {$EXTERNALSYM WSAVERNOTSUPPORTED}
  WSANOTINITIALISED      = WSABASEERR + 93;
  {$EXTERNALSYM WSANOTINITIALISED}
  WSAEDISCON             = WSABASEERR + 101;
  {$EXTERNALSYM WSAEDISCON}
  WSAENOMORE             = WSABASEERR + 102;
  {$EXTERNALSYM WSAENOMORE}
  WSAECANCELLED          = WSABASEERR + 103;
  {$EXTERNALSYM WSAECANCELLED}
  WSAEINVALIDPROCTABLE   = WSABASEERR + 104;
  {$EXTERNALSYM WSAEINVALIDPROCTABLE}
  WSAEINVALIDPROVIDER    = WSABASEERR + 105;
  {$EXTERNALSYM WSAEINVALIDPROVIDER}
  WSAEPROVIDERFAILEDINIT = WSABASEERR + 106;
  {$EXTERNALSYM WSAEPROVIDERFAILEDINIT}
  WSASYSCALLFAILURE      = WSABASEERR + 107;
  {$EXTERNALSYM WSASYSCALLFAILURE}
  WSASERVICE_NOT_FOUND   = WSABASEERR + 108;
  {$EXTERNALSYM WSASERVICE_NOT_FOUND}
  WSATYPE_NOT_FOUND      = WSABASEERR + 109;
  {$EXTERNALSYM WSATYPE_NOT_FOUND}
  WSA_E_NO_MORE          = WSABASEERR + 110;
  {$EXTERNALSYM WSA_E_NO_MORE}
  WSA_E_CANCELLED        = WSABASEERR + 111;
  {$EXTERNALSYM WSA_E_CANCELLED}
  WSAEREFUSED            = WSABASEERR + 112;
  {$EXTERNALSYM WSAEREFUSED}

//
// Error return codes from gethostbyname() and gethostbyaddr()
// (when using the resolver). Note that these errors are
// retrieved via WSAGetLastError() and must therefore follow
// the rules for avoiding clashes with error numbers from
// specific implementations or language run-time systems.
// For this reason the codes are based at WSABASEERR+1001.
// Note also that [WSA]NO_ADDRESS is defined only for
// compatibility purposes.
//

// Authoritative Answer: Host not found

  WSAHOST_NOT_FOUND = WSABASEERR + 1001;
  {$EXTERNALSYM WSAHOST_NOT_FOUND}

// Non-Authoritative: Host not found, or SERVERFAIL

  WSATRY_AGAIN = WSABASEERR + 1002;
  {$EXTERNALSYM WSATRY_AGAIN}

// Non-recoverable errors, FORMERR, REFUSED, NOTIMP

  WSANO_RECOVERY = WSABASEERR + 1003;
  {$EXTERNALSYM WSANO_RECOVERY}

// Valid name, no data record of requested type

  WSANO_DATA = WSABASEERR + 1004;
  {$EXTERNALSYM WSANO_DATA}

//
// Define QOS related error return codes
//
//

  WSA_QOS_RECEIVERS          = WSABASEERR + 1005// at least one Reserve has arrived
  {$EXTERNALSYM WSA_QOS_RECEIVERS}
  WSA_QOS_SENDERS            = WSABASEERR + 1006// at least one Path has arrived
  {$EXTERNALSYM WSA_QOS_SENDERS}
  WSA_QOS_NO_SENDERS         = WSABASEERR + 1007// there are no senders
  {$EXTERNALSYM WSA_QOS_NO_SENDERS}
  WSA_QOS_NO_RECEIVERS       = WSABASEERR + 1008// there are no receivers
  {$EXTERNALSYM WSA_QOS_NO_RECEIVERS}
  WSA_QOS_REQUEST_CONFIRMED  = WSABASEERR + 1009// Reserve has been confirmed
  {$EXTERNALSYM WSA_QOS_REQUEST_CONFIRMED}
  WSA_QOS_ADMISSION_FAILURE  = WSABASEERR + 1010// error due to lack of resources
  {$EXTERNALSYM WSA_QOS_ADMISSION_FAILURE}
  WSA_QOS_POLICY_FAILURE     = WSABASEERR + 1011// rejected for administrative reasons - bad credentials
  {$EXTERNALSYM WSA_QOS_POLICY_FAILURE}
  WSA_QOS_BAD_STYLE          = WSABASEERR + 1012// unknown or conflicting style
  {$EXTERNALSYM WSA_QOS_BAD_STYLE}
  WSA_QOS_BAD_OBJECT         = WSABASEERR + 1013// problem with some part of the filterspec or providerspecific buffer in general
  {$EXTERNALSYM WSA_QOS_BAD_OBJECT}
  WSA_QOS_TRAFFIC_CTRL_ERROR = WSABASEERR + 1014// problem with some part of the flowspec
  {$EXTERNALSYM WSA_QOS_TRAFFIC_CTRL_ERROR}
  WSA_QOS_GENERIC_ERROR      = WSABASEERR + 1015// general error
  {$EXTERNALSYM WSA_QOS_GENERIC_ERROR}
  WSA_QOS_ESERVICETYPE       = WSABASEERR + 1016// invalid service type in flowspec
  {$EXTERNALSYM WSA_QOS_ESERVICETYPE}
  WSA_QOS_EFLOWSPEC          = WSABASEERR + 1017// invalid flowspec
  {$EXTERNALSYM WSA_QOS_EFLOWSPEC}
  WSA_QOS_EPROVSPECBUF       = WSABASEERR + 1018// invalid provider specific buffer
  {$EXTERNALSYM WSA_QOS_EPROVSPECBUF}
  WSA_QOS_EFILTERSTYLE       = WSABASEERR + 1019// invalid filter style
  {$EXTERNALSYM WSA_QOS_EFILTERSTYLE}
  WSA_QOS_EFILTERTYPE        = WSABASEERR + 1020// invalid filter type
  {$EXTERNALSYM WSA_QOS_EFILTERTYPE}
  WSA_QOS_EFILTERCOUNT       = WSABASEERR + 1021// incorrect number of filters
  {$EXTERNALSYM WSA_QOS_EFILTERCOUNT}
  WSA_QOS_EOBJLENGTH         = WSABASEERR + 1022// invalid object length
  {$EXTERNALSYM WSA_QOS_EOBJLENGTH}
  WSA_QOS_EFLOWCOUNT         = WSABASEERR + 1023// incorrect number of flows
  {$EXTERNALSYM WSA_QOS_EFLOWCOUNT}
  WSA_QOS_EUNKOWNPSOBJ       = WSABASEERR + 1024// unknown object in provider specific buffer
  {$EXTERNALSYM WSA_QOS_EUNKOWNPSOBJ}
  WSA_QOS_EPOLICYOBJ         = WSABASEERR + 1025// invalid policy object in provider specific buffer
  {$EXTERNALSYM WSA_QOS_EPOLICYOBJ}
  WSA_QOS_EFLOWDESC          = WSABASEERR + 1026// invalid flow descriptor in the list
  {$EXTERNALSYM WSA_QOS_EFLOWDESC}
  WSA_QOS_EPSFLOWSPEC        = WSABASEERR + 1027// inconsistent flow spec in provider specific buffer
  {$EXTERNALSYM WSA_QOS_EPSFLOWSPEC}
  WSA_QOS_EPSFILTERSPEC      = WSABASEERR + 1028// invalid filter spec in provider specific buffer
  {$EXTERNALSYM WSA_QOS_EPSFILTERSPEC}
  WSA_QOS_ESDMODEOBJ         = WSABASEERR + 1029// invalid shape discard mode object in provider specific buffer
  {$EXTERNALSYM WSA_QOS_ESDMODEOBJ}
  WSA_QOS_ESHAPERATEOBJ      = WSABASEERR + 1030// invalid shaping rate object in provider specific buffer
  {$EXTERNALSYM WSA_QOS_ESHAPERATEOBJ}
  WSA_QOS_RESERVED_PETYPE    = WSABASEERR + 1031// reserved policy element in provider specific buffer
  {$EXTERNALSYM WSA_QOS_RESERVED_PETYPE}

// Error codes from getaddrinfo()

const
  EAI_AGAIN    = WSATRY_AGAIN;
  {$EXTERNALSYM EAI_AGAIN}
  EAI_BADFLAGS = WSAEINVAL;
  {$EXTERNALSYM EAI_BADFLAGS}
  EAI_FAIL     = WSANO_RECOVERY;
  {$EXTERNALSYM EAI_FAIL}
  EAI_FAMILY   = WSAEAFNOSUPPORT;
  {$EXTERNALSYM EAI_FAMILY}
  EAI_MEMORY   = 8;          // WSA_NOT_ENOUGH_MEMORY
  //EAI_MEMORY   = WSA_NOT_ENOUGH_MEMORY;
  {$EXTERNALSYM EAI_MEMORY}
//#define EAI_NODATA      WSANO_DATA
  EAI_NONAME   = WSAHOST_NOT_FOUND;
  {$EXTERNALSYM EAI_NONAME}
  EAI_SERVICE  = WSATYPE_NOT_FOUND;
  {$EXTERNALSYM EAI_SERVICE}
  EAI_SOCKTYPE = WSAESOCKTNOSUPPORT;
  {$EXTERNALSYM EAI_SOCKTYPE}

  ws2tcpip = 'ws2_32.dll';

//
//  DCR_FIX:  EAI_NODATA remove or fix
//
//  EAI_NODATA was removed from rfc2553bis
//  need to find out from the authors why and
//  determine the error for "no records of this type"
//  temporarily, we'll keep #define to avoid changing
//  code that could change back;  use NONAME
//

  EAI_NODATA = EAI_NONAME;
  {$EXTERNALSYM EAI_NODATA}

// Structure used in getaddrinfo() call

type
  LPADDRINFO = ^addrinfo;
  {$EXTERNALSYM LPADDRINFO}
  addrinfo = record
    ai_flags    : Integer;     // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
    ai_family   : Integer;     // PF_xxx
    ai_socktype : Integer;     // SOCK_xxx
    ai_protocol : Integer;     // 0 or IPPROTO_xxx for IPv4 and IPv6
    ai_addrlen  : Integer;     // Length of ai_addr
    ai_canonname: PChar;       // Canonical name for nodename
    ai_addr     : PSockAddr;   // Binary address
    ai_next     : LPADDRINFO;  // Next structure in linked list
  end;
  {$EXTERNALSYM addrinfo}
  TAddrInfo = addrinfo;
  PAddrInfo = LPADDRINFO;

// Flags used in "hints" argument to getaddrinfo()

const
  AI_PASSIVE     = $1// Socket address will be used in bind() call
  {$EXTERNALSYM AI_PASSIVE}
  AI_CANONNAME   = $2// Return canonical name in first ai_canonname
  {$EXTERNALSYM AI_CANONNAME}
  AI_NUMERICHOST = $4// Nodename must be a numeric address string
  {$EXTERNALSYM AI_NUMERICHOST}

function getaddrinfo(nodename, servname: PChar; hints: PAddrInfo; var res: PAddrInfo): Integer; stdcall;
{$EXTERNALSYM getaddrinfo}

procedure freeaddrinfo(ai: PAddrInfo); stdcall;
{$EXTERNALSYM freeaddrinfo}



implementation

function getaddrinfo; external ws2tcpip name 'getaddrinfo';
procedure freeaddrinfo; external ws2tcpip name 'freeaddrinfo';

end.


Grüße von der heute sonnigen Nordsee

Peter


Delete - Sa 04.04.15 15:02

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Perlsau, wenn hier jemand mit gefählichem Halbwissen unterwegs ist dann ja wohl Du!!

Gefährliches Halbwissen? Von welcher angeblichen Gefahr schreibst du denn hier?

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Wer nicht einmal weiß, dass Systemschnittstellen nur per CPU-Debug untersucht werden können, sollte keine solchen Sprüche machen.

Wie kommst du darauf, daß ich das nicht wüßte? Mußt du jetzt schon Sachen erfinden, nur weil du keine Kritik vertragen kannst?

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du hilfreiche Beiträge hast sind die willkommen! Wenn Du weiter nur dumme Sprüche auf Lager hast muß ich Deine Beiträge wohl nochmals melden.

Meine Beiträge? Alle? Nochmals melden? Was hattest du denn bisher zu vermelden?

Tipp von mir: lies das Folgende mal ganz genau und in Ruhe durch:

Wenn du dich falsch ausdrückst, indem du schreibst, du hast eine Zeile in deinem Code in Verdacht, einen bestimmten Fehler auszulösen, obwohl du angeblich genau wußtest, daß der Fehler in dieser Zeile entsteht, darfst du dich nicht wundern, wenn man dir den Rat gibt, an dieser Zeile einen Breakpoint zu setzen, um aus dem Verdacht Gewißheit werden zu lassen. Hier hast du dich gleich mordsmäßig aufgeregt und mir unterstellt, ich wolle dich für dumm verkaufen, statt das einfach so stehen zu lassen und dich den für dich hilfreichen Beiträgen zuzuwenden. Und obwohl ich in jenem anderen Thread dieses Mißverständnis sofort aufgeklärt habe, beharrst du weiterhin darauf, daß das angeblich so gemeint war, wie du es mir unterstellst. Ich habe diese beleidigende Unterstellung nicht gemeldet, weil ich der Meinung war, du kannst meinen Versuch, das Mißverständnis aufzuklären, nachvollziehen und man ja nicht alles gleich melden muß. Offenbar habe ich mich geirrt: Du hattest nichts Besseres zu tun, als damit fortzufahren, mich in den folgenden Beiträgen weiter zu beleidigen, woraufhin ich dich verwarnt hatte. Was glaubst du eigentlich, wer du bist? Woher nimmt du das Recht, über andere öffentlich zu urteilen?

Wenn ich nun angesichts deiner widersinnigen und nachweislich falschen Behauptung, ein PChar sei ein doppelter Pointer, Halbwissen (mangelhaftes, oberflächliches Wissen [http://www.duden.de/rechtschreibung/Halbwissen]) bei dir vermute, scheinst du dich sofort wieder beleidigt zu fühlen. Es ist aber nunmal Fakt, daß du hier kein fundiertes Wissen aufzuweisen hast und man deine Kenntnisse hier ohne Wenn und Aber als unzureichend bezeichnen muß. Daher ist es auch legitim, darauf bzw. auf die daraus resultierenden Fehlerquellen hinzuweisen. Mit anderen Worten: Man ist immer gut beraten, beim Programmieren nicht nur herumzuraten, sondern sich fundiertes Grundlagenwissen anzugeignen, bevor man daran geht, komplexe Aufgaben bewältigen zu wollen. Das möchtest du offenbar nicht wissen, sondern dich hier als kenntnisreich und erfahren darstellen. Du zeigst damit vor allem ein äußerst unreifes Verhalten, das darin gipfelt, mich mit meinen 54 Jahren als als jung und unreif hinstellen zu wollen. (Man untestellt anderen am liebsten den Dreck, den man selbst am Stecken hat, weil man sich damit am besten auskennt.)

Ich wünsche dir trotz allem ein schönes Osterfest und viel Erfolg beim Nachreifen.


Peter18 - Sa 04.04.15 15:26

Hallo Perlsau,

wenn Du nichts sachdienliches beizutragen hast, halt Dich aus den Diskussionen raus! Derartige Beiträge werde ich nicht weiter kommentieren, dafür ist mir die Zeit zu schade!


Delete - Sa 04.04.15 15:58

Mit "sachdienlichen Hinweisen" meinst du vermutlich so Sachen wie:


Und da du, wie versprochen, nicht mehr darauf antworten wirst, zum "Abschied" noch ein guter Rat von mir: Immer erst an die eigene Nase fassen :wink:


jaenicke - Sa 04.04.15 19:34

user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
selbstverständlich! Genügt die Unit oder auch die "winsock.pas" und die Projektdatei?
Am einfachsten ist es immer einfach die Dateien, die zum Projekt gehören in ein Zip zu packen und so anzuhängen. ;-)
Das ist soweit der Server, fehlt noch der Client um das zu testen.

// EDIT:
Bzw. ich sehe gerade... soll der Timer den Client machen? Das kann nicht gehen, denn dein Hauptthread hängt ja im accept. Da brauchst du ein zweites Programm oder Threads.


WasWeißDennIch - Sa 04.04.15 19:34

Und Eure Kindergarten-Streitereien klärt doch besser per PM, das gehört hier nicht her.


Peter18 - So 05.04.15 13:17

Hallo Sebastian,

Dank Dir für Deine Antwort. Ich hatte schon Schwierigkeiten Dateien von anderen Compilerversionen anzupassen, daher habe ich nicht alles bereitgestellt. Aber nun ist alles in der 7z, inklusive der Delphi 4 Winsock. Wenn noch etwas fehlt, stelle ich es gern bereit.

Wie schon gesagt, alles quick and dirty, um erst mal eine Übersicht zu gewinnen und experimentieren zu können. Ich habe noch keine Threads verwendet, statt dessen werden Tasten und Timer zum Starten der Fonktionen verwendet.

Laut MS-Beispiel soll der Text im Puffer enthalten sein. Die Parameter werden von hinten (Flag=0 zuerst) auf den Stack gelegt. Vom Enpfangspuffer wird die Variablenaderesse abgelegt. Wenn ich statt dessen die Pufferadresse auf den Stack lege bleibt das Ergebnis das gleiche.

Ich hoffe auf einen guten Tipp.

Hallo WasWeißDennIch,

Dank auch Dir für Deinen Beitrag! Manch einer weiß eben nicht wann es genug ist.

Grüße von der auch heute sonnigen Nordsee

Peter


jaenicke - So 05.04.15 20:43

Du hast einen Fehler mit den Buffern drin, ansonsten funktioniert das schon. Du musst bei send und recv keinen Pointer angeben, sondern einen Puffer. Nimm als Buffer einfach einen AnsiString. Senden:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  Res: Integer;
  Buf: AnsiString;
begin
  Memo1.Lines.Add('Sende: ' + Edit3.Text);
  Buf := Edit3.Text;
  Res := send(CSock, Buf[1], Length(Buf), 0);
Empfangen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var
  Res: Integer;
  recvbuf: AnsiString;
begin
  SetLength(recvbuf, BuffSize);
  Res := recv(CSock, recvbuf[1], BuffSize, 0);
  if Res >= 0 then
  begin
    Memo1.Lines.Add(IntToStr(Res) + ' Zeichen empfangen.');
    SetLength(recvbuf, Res);
    Memo1.Lines.Add('Text: ' + recvbuf);
Wichtig ist bei recv auch der letzte Parameter. Ich weiß ehrlich gesagt nicht was dein MSG_OOB (das ist ja die 1) bewirkt, aber damit bleibt der Aufruf hängen.
Außerdem müsstest du das noch in einen Thread packen, damit dein Server noch reagiert oder MSG_PEEK benutzen um erst einmal zu schauen was da ist.


Peter18 - Mo 06.04.15 10:47

Hallo Sebastian,

danke für Deine Hilfe! Von C nach Delphi ist doch nicht so tivial. Auf "SetLength(recvbuf, Res);" wär ich nicht so schnell gekommen. Nun reden sie miteinander und ich kann mitlesen. :D :D :D

"MSG_OOB" hatte ich nur mal probiert, weil ich die Flags nicht gefunden habe. Ich wollte wissen, was "MSG_PEEK" ist aber Banane. Irgend wann hatte ich die Flags gesehen, aber nicht wieder gefunden. Falls Du einen Link oder eine Konstantendeklaration hast wär ich Dir dankbar!

Grüße von der noch immer sonnigen Nordsee

Peter


jaenicke - Mo 06.04.15 11:03

Du kannst einfach in die in der Doku angegebene Headerdatei aus dem Windows SDK schauen. MSG_OOB = $0001, MSG_PEEK = $0002 und MSG_WAITALL = $0100.


Peter18 - Mo 06.04.15 12:48

Hallo Sebastian,

Dank Dir!

Grüße von der Nordsee

Peter


Peter18 - Mo 06.04.15 17:45

Ein freundliches Hallo an alle,

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ich weiß ehrlich gesagt nicht was dein MSG_OOB (das ist ja die 1) bewirkt, aber damit bleibt der Aufruf hängen.

Beim studieren der Winsockbeschreibungen bin ich darauf gestoßen (sehr speziel):
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740102%28v=vs.85%29.aspx

Grüße von der Nordsee

Peter