Autor Beitrag
jakobwenzel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Do 01.09.05 20:22 
Ich bin dabei mit den Indys (version 10) einen TCP-Chat (TidTCPServer und TidTCPClient) zu programmieren. Server und Client sind in einem Programm, man muss beim Starten auswählen, ob man Client oder Server ist. Die Clients können schon Nachrichten senden, auch die Meldung, dass ein neuer Benutzer hinzugekommen ist funktioniert schon. Da idTCPServer1.Contexts.LockList irgendwie das Programm lahmlegt, wenn man es z.B. in einer Button-Click-Routine aufruft, habe ich mir gedacht, ich könnte die vorhandene idTcpClient-Komponente nutzen. Aber jetzt ist es so, dass der Host nur senden kann, wenn kein Client verbunden ist. Wenn ein Client verbunden ist, kann der Host keine Nachrichten mehr senden (keine Fehlermeldung, alles wird korrekt ausgeführt, nur keine Nachricht). Hat der Host Nachrichten gesendet, bevor der Client sich anmeldete, kann der Client auch keine Nachrichten mehr senden. Warum geht das nicht?

P.S.:Ich habe mal das Projekt drangehängt...
Einloggen, um Attachments anzusehen!
_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
GTA-Place
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
EE-Regisseur
Beiträge: 5248
Erhaltene Danke: 2

WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
BeitragVerfasst: Fr 02.09.05 13:02 
Kannst du bitte den Source hier reinstellen.
Ich habe keine Lust für jedes Problem das Projekt erst herunterzuladen.
Danke.

_________________
"Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 02.09.05 13:07 
Hallo!

Schau mal in die Open-Source-Units Sparte, da gibt´s die SimpleTCP-Units nun auch für Indy10. Da hat man die Probleme mit dem Synchronisieren etc. nicht.

Cu,
Udontknow
jakobwenzel Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Fr 02.09.05 15:06 
@GTA-Place:

ausblenden volle Höhe 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:
unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Menus, IdServerIOHandler, IdServerIOHandlerSocket,
  IdServerIOHandlerStack, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack,
  IdTCPServer, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  ExtCtrls, Mask, idStack, idcontext;

const
  Join    = 'Joi ';
  Msg     = 'Msg ';
  trenner :String'|';


type
  TForm2 = class(TForm)
    IdTCPClient: TIdTCPClient;
    IdTCPServer: TIdTCPServer;
    IdIOHandlerStack: TIdIOHandlerStack;
    IdServerIOHandlerStack: TIdServerIOHandlerStack;
    Port: TLabel;
    EditPort: TEdit;
    RadioGroupType: TRadioGroup;
    LabelNick: TLabel;
    EditNick: TEdit;
    LabelNachricht: TLabel;
    EditMessage: TEdit;
    ButtonLogIn: TButton;
    ButtonSend: TButton;
    ListBox1: TListBox;
    Label1: TLabel;
    MaskEditHostIp: TMaskEdit;
    Timer1: TTimer;
    procedure ButtonSendClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure IdTCPServerExecute(AContext: TIdContext);
    procedure ButtonLogInClick(Sender: TObject);
    procedure RadioGroupTypeClick(Sender: TObject);
    procedure EditPortChange(Sender: TObject);
    procedure EditPortKeyPress(Sender: TObject; var Key: Char);
    procedure DisableLoginButtons;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.DisableLoginButtons;
begin
  ButtonLogIn.Enabled:=false;
  EditPort.Enabled:=false;
  EditNick.Enabled:=false;
  MaskEditHostIp.Enabled:=false;
  RadioGroupType.Enabled:=false;
end;

procedure TForm2.EditPortKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['0'..'9',#8]) then begin
    Beep;
    Key:=#0;
  end;
end;

procedure TForm2.EditPortChange(Sender: TObject);
begin
  IdTCPClient.Port:=StrToInt(EditPort.Text);
  IdTCPServer.DefaultPort:=StrToInt(EditPort.Text);
end;

procedure TForm2.RadioGroupTypeClick(Sender: TObject);
begin
  if RadioGroupType.ItemIndex=1 then begin
    MaskEditHostIp.Enabled:=true;
    MaskEditHostIp.Color:=clWindow;
  end else begin
    MaskEditHostIp.Enabled:=false;
    MaskEditHostIp.Color:=clBtnFace;
  end;
end;

procedure TForm2.ButtonLogInClick(Sender: TObject);
var
  str:String;
begin
  (Sender as TButton).Caption:='Verbinde...';
  try
    try
      if RadioGroupType.ItemIndex=0 Then begin //Host
        IdTCPServer.Active:=true;
        DisableLoginButtons;
        IdTCPClient.Host:='127.0.0.1';
        IdTcpClient.Connect;
      end else begin                           //Client
        IdTCPClient.Host:=MaskEditHostIp.Text;
        IdTCPClient.Connect;
        DisableLoginButtons;
        IdIOHandlerStack.WriteLn(Join+EditNick.Text);
        Timer1.Enabled:=true;
      end;
    except
      on E: EidSocketError do begin
        case E.LastError of
          10061: str:='Auf der Angegebenen Ip läuft unter dem angegebenen Port kein Server!';
          10060: str:='Die angegebene IP exisitiert nicht.';
        else str:='Konnte nicht verbinden.'
        end;
        MessageDlg(str,mtError,[mbOK],0);
      end;
    end;
  finally
    (Sender as TButton).Caption:='Einloggen';
  end;
end;

function Cut(s:String;start,count:Integer):String;
var
  i:Integer;
  nstr:String;
begin
  if start>Length(s) then result:=s;
  if (start+count>Length(s)) or (count<=0Then
   count:=Length(s)-start;
  nstr:='';
  for i:=start To (start+count) do begin
    nstr:=nstr+s[i];
  end;
  result:=nstr;
end;

procedure TForm2.IdTCPServerExecute(AContext: TIdContext);
var
  lRow, lCmd:String;
  list:TList;
  i:Integer;
  Row,nick,nachricht:String;
begin
  lRow:=Trim(AContext.Connection.IOHandler.ReadLn);
  lCmd:=lRow;
  SetLength(lCmd,4);
  If AnsiSameText(lCmd, Join) Then begin
    List := idTcpServer.Contexts.LockList;
    row:= (Cut(lRow,5,-1))+' hat den Chat betreten.';
    for i:=0 to List.Count-1 do
      tIdContext(List.Items[i]).Connection.IOHandler.WriteLn(row);
    ListBox1.AddItem(row,nil);
  end else if AnsiSameText(lCmd, Msg) then begin
    nick:=Cut(lRow, 5, (Pos(Trenner,lRow)-6));
    nachricht:=Cut(lRow,(Pos(Trenner,lRow)+1),-1);
    List := idTcpServer.Contexts.LockList;
    row:= nick+': '+nachricht;
    for i:=0 to List.Count-1 do
      tIdContext(List.Items[i]).Connection.IOHandler.WriteLn(row);
    ListBox1.AddItem(row,nil);
  end;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  while IdIOHandlerStack.Readable(0do ListBox1.AddItem(IdIOHandlerStack.ReadLn,nil);
end;

procedure TForm2.ButtonSendClick(Sender: TObject);
var
  list:TList;
  row:String;
  i:Integer;
begin
//  if RadioGroupType.ItemIndex=1 Then
    IdIOHandlerStack.WriteLn(Msg+EditNick.Text+Trenner+EditMessage.Text);
{  else begin
    row:= EditNick.Text+': '+EditMessage.Text;
    list := idTcpServer.Contexts.LockList;
    for i:=0 to List.Count-1 do
      tIdContext(List.Items[i]).Connection.IOHandler.WriteLn(row);
    ListBox1.AddItem(row,nil);
  end;}

end;

end.


@Udontknow: Ich schau mal...

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 02.09.05 15:12 
Hallo!

Habe kurz den Code überflogen:

In deiner Execute-Routine rufst du gar nicht Unlocklist auf. Also bleibt die Liste auf ewig gesperrt für andere Threads wie die TCP-Input-Threads...

[Werbung]Das Problem hättest du mit den SimpleTCP-Sachen nicht... :wink: [/Werbung]

Cu,
Udontknow
jakobwenzel Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1889
Erhaltene Danke: 1

XP home, ubuntu
BDS 2006 Prof
BeitragVerfasst: Fr 02.09.05 15:41 
Danke!! Das war der Fehler!!! :D :D :D
Ich hab die Indys erst seit zwei Tagen und kann halt noch nicht so gut damit umgehen. Deshalb will ich es auch selber machen und nicht die SimpleTcpSachen nutzen.

_________________
I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 02.09.05 15:48 
Deine Vorgehensweise ist aber trotzdem nicht threadsicher. Du erreichst zwar mit Locklist/Unlocklist eine Synchronisation mit den anderen InputThreads, nicht aber mit dem VCL-Hauptthread. Trotzdem greifst du in der Execute-Routine auf Steuerelemente zu. Alle Steuerelemente sind nicht von sich aus threadsicher, nur der VCL-Hauptthread darf sie manipulieren! Ansonsten kann alles passieren, von Zugriffsschutzverletzungen bis zum kompletten Programmabbruch.

Schau mal in der Delphi-Hilfe unter Synchronize, wie man das hinbekommt. Alternativ kannst du natürlich (Achtung, wieder Werbung!) den Code der SimpleTCP-Komponenten begutachten, die das ja berücksichtigen...

Cu,
Udontknow