Solved

Problem with sockets.

Posted on 2001-06-12
9
273 Views
Last Modified: 2010-04-06
Ok, I'm new to the whole socket programming thing, so I probably just have some bad code. Basically I need someone to figure out the bad parts of this code, basically, if you can't see what I'm trying to do here, you have no buisiness helping me. Blunt but honest, sorry.

Here'a a large portion of my source there are some things here that don't have any releavance but here they are anyways... Basically what I want to do is send these numeric commands to the client and server... I have written a beginning to the procedure that is supposed to parse them, but when I stop on the code that reads the socket, it just says "()" which I guess means nil, I dunno if I'm using the wrong method here or what. But basically I don't want to have to limit the amount of users that can connect so this is not a client/server only I have in mind here... the person that hosts connects to their own server upon doing so, and everything is handled that way (or is supposed to be) I hope someone can make sense of this code cause I don't know where I'm going wrong.

Thanks,

Psylord


procedure TForm1.FormShow(Sender: TObject);
begin
MyNickName := 'Psylord';
end;

procedure TForm1.Echo(Content: String);
begin
Memo1.Lines.Add(Content);
end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin

if key = #13 then
 begin
  key := #0; {Ditch the beep}
  if not Connected then
   begin
    Echo('*Not Connected');
   end;
 {We're Connected, Send the command:}
//Not implemented yet
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Users := TStringList.Create;
end;

procedure TForm1.JoinServer(Host: String; Port: Integer);
begin
{Here's where we connect}
Client.Port := Port;
Client.Host := Host;
Client.Active := True;
end;

procedure TForm1.BeginHost(Port: Integer);
begin
{Let's start the server}
Server.Port := Port;
Server.Active := True;
Application.ProcessMessages;
{We need to join our own server now}
JoinServer('localhost', ServerPort);
end;

procedure TForm1.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
Echo('*Connection request: ' + Socket.RemoteAddress + ':' + IntToStr(Socket.LocalPort) + ' requesting authentication.');
end;

procedure TForm1.ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
Connected := True; {We're Connected to the server}
Echo('*Connected to server: ' + Socket.RemoteAddress + ':' + IntToStr(Socket.RemotePort) + ' sending authentication.');
SendToServer(100, MyNickName, Socket);
end;

procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
    Line: string;
    I: Integer;
    FReceiveBuffer: String;
begin
 FReceiveBuffer:=FReceiveBuffer+Socket.ReceiveText;
 I:=Pos(#13,FReceiveBuffer);
 while I>0 do begin
  Line:=Copy(FReceiveBuffer,1,I-1);
  Delete(FReceiveBuffer,1,I);
  Line:=StringReplace(StringReplace(Line,'\n',#13,[rfReplaceAll]),'\\','\',[rfReplaceAll]);
  I:=Pos(' ',Line);
  ParseCommand(Socket, StrToInt(Copy(Line,1,I-1)), Copy(Line, I+1, Length(Line)));
  I:=Pos(#13,FReceiveBuffer);
 end;

end;

procedure TForm1.ParseCommand(Socket: TCustomWinSocket; Numeric: Integer; Content: String);
begin

 case Numeric of
  100:
   begin
   Echo('*Debug: 100 recvd');
    {The numeric was "100"!}
{    Client.Socket.SendText(IntToStr(Numeric) + ' ' + Content);
    Server.Socket.SendText(IntToStr(Numeric) + ' ' + Content);}
   end;

 end; {Case}

end; {Proc}

procedure TForm1.SendToServer(Numeric: Integer; Content: String; Socket: TCustomWinSocket);
begin
Socket.SendText(Format('%d %s',[Numeric,StringReplace(StringReplace(Content,'\','\\',[rfReplaceAll]),#13,'\n',[rfReplaceAll])]));
end;

procedure TForm1.SendToClient(Numeric: Integer; Content: String; Socket: TCustomWinSocket);
begin
Socket.SendText(Format('%d %s',[Numeric,StringReplace(StringReplace(Content,'\','\\',[rfReplaceAll]),#13,'\n',[rfReplaceAll])]));
end;

procedure TForm1.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
    Line: string;
    I: Integer;
    FReceiveBuffer: String;
begin
 FReceiveBuffer:=FReceiveBuffer+Socket.ReceiveText;
 I:=Pos(#13,FReceiveBuffer);
 while I>0 do begin
  Line:=Copy(FReceiveBuffer,1,I-1);
  Delete(FReceiveBuffer,1,I);
  Line:=StringReplace(StringReplace(Line,'\n',#13,[rfReplaceAll]),'\\','\',[rfReplaceAll]);
  I:=Pos(' ',Line);
  ParseCommand(Socket, StrToInt(Copy(Line,1,I-1)), Copy(Line, I+1, Length(Line)));
  I:=Pos(#13,FReceiveBuffer);
 end;
end;


If this can be fixed the way I want it to be, that would rock heavy metal style!! *Dances upside down*


I do low points cause I'm getting low and this should be easy to any socks expert. Sorry.
0
Comment
Question by:Psylord
9 Comments
 
LVL 12

Expert Comment

by:rwilson032697
ID: 6184768
When you say "... is just says '()', I guess that means nil...' you mean when you inspect its value via a tool tip?

Delphi usually does this if it can't determine the class of the item being pointed eg (eg: it is the 'sender' which is usually TObject...). It does not mean thats its value is nil, otherwise the tooltip would have said so.

You can examine its values by casting the item in the watch window (eg: TMyObject(Sender) )

Cheers,

Raymond.
0
 

Author Comment

by:Psylord
ID: 6185171
Yeah ok. That's what I meant, when I put a breakpoint onit it did what you just said. I still don't know what I'm doing wrong though. The data just isn't being handled correctly and I dunno what else to do. :(
0
 
LVL 4

Expert Comment

by:Colin_Dawson
ID: 6185393
I've not looked at the code in detail, But I can see that you're using the TClientSocket & TServerSocket.  I tried to use this and found them quite complicated.  Just a thought, but have you considered using the INDY components (a.k.a WinShoes).  They're open source and also part of Kylix and Delphi 6.  You can download them free from

http://www.nevrona.com/Indy/

Regards

Colin Dawson
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6187812
Could you post a listing of the output when you run this?  That would help me.  Also, in the following code:

procedure TForm1.BeginHost(Port: Integer);
begin
{Let's start the server}
Server.Port := Port;
Server.Active := True;
Application.ProcessMessages;
{We need to join our own server now}
JoinServer('localhost', ServerPort);
end;

Where are you getting "ServerPort" in the last line?  Should that be "Server.Port"?

Eric
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:Psylord
ID: 6188082
Colin, I tried indy and it gave me an error when I started Delphi.

Eric,

You're right ServerPort should actually be changed to "Port"

There is no output generated, so I can't give any to you... There are no errors in the actual code, but then on the other hand, it's not getting the data for some reason.

0
 
LVL 1

Expert Comment

by:edsteele
ID: 6188134
No output?  But, you have a call to "Echo" in both connect methods.  This seems to tell me that you are not getting a connection at all.

Why don't you try adding some calls to "echo" in your problem spots and look at data that way.  I would place one at the beginning and end of each method you use, then place another in every location something significant happens.  This should give a very nice "trace" of the program execution.  If you can post that, then we can really help you.

Eric
0
 

Author Comment

by:Psylord
ID: 6188301
My echo is just there as one of the non relevant procedures I mentioned above. It is connecting, because my onconnect events are being triggered ok.

In my connect event for my Client socket, I try to send a numeric to the server, that's where the problem must be, it doesn't seem to be sending right.

0
 
LVL 1

Accepted Solution

by:
edsteele earned 150 total points
ID: 6191451
The echo may be non-relevant, but it can be invaluable for debugging purposes.

Anyway, I found your problem.  The problem isn't in the code as much as in the data you are passing to the sockets.  I pasted the code you supplied into a new project and sprinkled it with Echo statements.  The ServerClientRead is being executed, but it is not finding anything (Well, your code isn't finding anything, ServerClientRead did get the string).  The problem is your use of the #13 character.  When you sent your nickname to the server, there was no #13 behind it, so your code in ServerClientRead thinks there is nothing to look at.

My solution is to replace the #13 with #182(the paragraph symbol).  Also change the code in SendToServer and SendToClient to do something like:

  Socket.SendText(Format('%d %s'#182,[Numeric,StringReplace(StringReplace(Content,'\','\\',[rfReplaceAll]),#13,'\n',[rfReplaceAll])]));

You may be able to shorten that StringReplace stuff now, since the #13 will not be needed.

When I made these changes, it found your nickname and I got the proper response from the ParseCommand procedure.

Enjoy!
Eric
0
 

Author Comment

by:Psylord
ID: 6192767
Thanks! Works great! Appreciate the help. Increased points by 100. Sorry, all I can spare right now.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now