Autor |
Beitrag |
jakobwenzel
      
Beiträge: 1889
Erhaltene Danke: 1
XP home, ubuntu
BDS 2006 Prof
|
Verfasst: 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
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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 
      
Beiträge: 1889
Erhaltene Danke: 1
XP home, ubuntu
BDS 2006 Prof
|
Verfasst: Fr 02.09.05 15:06
@GTA-Place:
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 public 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 IdTCPServer.Active:=true; DisableLoginButtons; IdTCPClient.Host:='127.0.0.1'; IdTcpClient.Connect; end else begin 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<=0) Then 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(0) do ListBox1.AddItem(IdIOHandlerStack.ReadLn,nil); end;
procedure TForm2.ButtonSendClick(Sender: TObject); var list:TList; row:String; i:Integer; begin IdIOHandlerStack.WriteLn(Msg+EditNick.Text+Trenner+EditMessage.Text);
end;
end. |
@Udontknow: Ich schau mal...
_________________ I thought what I'd do was, I'd pretend I was one of those deaf-mutes.
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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...  [/Werbung]
Cu,
Udontknow
|
|
jakobwenzel 
      
Beiträge: 1889
Erhaltene Danke: 1
XP home, ubuntu
BDS 2006 Prof
|
Verfasst: Fr 02.09.05 15:41
Danke!! Das war der Fehler!!!
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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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
|
|
|