【发布时间】:2017-01-18 19:35:59
【问题描述】:
如果你们中的一些人有时间和耐心帮助我解决我的问题,我将不胜感激
我正在编写一个简单的 delphi 聊天程序(客户端/服务器套接字),我想将其转换为一个迷你游戏。该代码适用于本地主机,但是当我将服务器或客户端发送给朋友时,客户端无法连接到服务器。 我们俩都在使用路由器。此外,我认为 ISP 为我们提供 IP 的方式有些问题。我的意思是:“ipconfig”显示我有 192.168.x.x ;但是像“whatismyip.com”这样的网站向我显示了一个不同的地址。而且我不使用任何VPN。函数 TForm1.GetIPAddress 显示 192.168.x.x 之一。
那么,问题是:我应该如何编写聊天程序?鉴于上述连接问题,我必须使用哪些选项来连接服务器和客户端?
这是服务器的代码:
unit Unit1;
interface
uses
Windows, Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Win.ScktComp,
Vcl.ExtCtrls, winsock;
type
TForm1 = class(TForm)
server: TServerSocket;
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Label1: TLabel;
Label3: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Panel1: TPanel;
Panel2: TPanel;
Button3: TButton;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
procedure serverClientConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure serverClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure Button2Click(Sender: TObject);
procedure FormShow(Sender: TObject);
Function GetIPAddress:String;
procedure serverClientRead(Sender: TObject; Socket: TCustomWinSocket);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
server.Port:=strtoint(edit2.Text);
server.Active:=true;
Memo1.Lines.Add('server started');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
server.Active:=false;
memo1.Lines.Add('server stopped');
end;
procedure TForm1.Button3Click(Sender: TObject);
var
i: integer;
Str:String;
begin
Str:=Edit3.Text;
Memo1.Lines.Add('server: '+Str);
Edit3.Text:='';
for i:=0 to server.Socket.ActiveConnections-1 do
server.Socket.Connections[i].SendText(str);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
edit1.Text:=getipaddress;
end;
procedure TForm1.serverClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
memo1.Lines.Add('client connected '+socket.RemoteAddress);
end;
procedure TForm1.serverClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
memo1.Lines.Add('client disconnected'+socket.RemoteAddress);
end;
procedure TForm1.serverClientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
memo1.Lines.Add('client: '+socket.ReceiveText);
end;
Function TForm1.GetIPAddress:String;
type
pu_long = ^u_long;
var
varTWSAData : TWSAData;
varPHostEnt : PHostEnt;
varTInAddr : TInAddr;
namebuf : Array[0..255] of AnsiChar;
begin
If WSAStartup($101,varTWSAData) <> 0 Then
Result := 'No. IP Address'
Else Begin
gethostname(namebuf,sizeof(namebuf));
varPHostEnt := gethostbyname(namebuf);
varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
Result := inet_ntoa(varTInAddr);
End;
WSACleanup;
end;
end.
对于客户来说:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
System.Win.ScktComp, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
client: TClientSocket;
Label1: TLabel;
Label2: TLabel;
Button3: TButton;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
procedure clientConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure Button2Click(Sender: TObject);
procedure clientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure clientRead(Sender: TObject; Socket: TCustomWinSocket);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
client.Address:=edit1.Text;
client.Port:=strtoint(edit2.Text);
client.Active:=true;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
client.Active:=false;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
if client.Active then begin
client.Socket.SendText(edit3.Text) ;
memo1.Lines.Add('client :'+edit3.Text);
edit3.Text:='';
end
else showmessage('not connected');
end;
procedure TForm2.clientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
memo1.Lines.Add('connected') ;
end;
procedure TForm2.clientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
memo1.Lines.Add('disconnected') ;
end;
procedure TForm2.clientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
memo1.Lines.Add('server: '+socket.ReceiveText)
end;
end.
【问题讨论】:
-
您的问题与 Delphi 几乎没有关系,真的。您需要使用外部/WAN IP 地址(“whatsmyip”为您提供的地址)来连接和配置路由器以进行端口转发。把你的问题分解成碎片:首先,让你的程序单独在你的机器上运行,客户端和服务器(这是你问题的 Delphi 部分);然后您将学习如何在路由器上转发端口。
-
这不是真正的编码问题,而是网络问题,所以它属于ServerFault而不是StackOverflow。
-
我明白了,谢谢大家。我可以在 hamachi 之类的 VPN 的帮助下使用服务器/客户端吗?
-
客户端/服务器在任何 TCP/IP 连接上都可以正常工作,无论是否是 VPN。重要的是您了解客户端和服务器之间的网络连接布局,以便客户端可以连接到正确的主机名/IP。如果两台机器在同一个 LAN 上,即使通过 VPN,客户端也可以连接到服务器的 LAN IP。否则,客户端必须通过 Internet 连接到服务器的 ISP 分配的公共 IP。