如果你们中的一些人有时间和耐心帮我解决问题,我会很感激
我正在编写一个简单的delphi聊天程序(客户端/服务器套接字),我希望将其转换为迷你游戏。该代码适用于localhost,但是当我将服务器或客户端发送给朋友时,客户端无法连接到服务器。 我们俩都在使用路由器。此外,我认为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.
答案 0 :(得分:2)
我们都在使用路由器
您必须在服务器的路由器上配置端口转发规则。
通过服务器端路由器的入站连接必须从路由器的公共WAN IP /端口转发到服务器计算机的专用LAN IP /端口。然后,外部的出站客户端可以连接到服务器路由器的公共IP /端口:
client -> internet -> router (104.34.x.x:YYYY) -> server (192.168.x.x:ZZZZ)
如果服务器的路由器从ISP收到动态IP(这是家庭网络中的常见情况),则IP将定期更改。您可以改为使用动态DNS服务(例如DynDNS,No-IP,Dynu,DuckDNS等)来创建静态主机名,解析为当前IP发生的任何情况,而不是在您想要连接时手动查找当前IP。是(大多数路由器都有内置选项,可在路由器IP更改时自动更新此类服务)。然后,客户端可以直接连接到主机名而不是路由器的IP:
client.Host := 'myDynDNShostname';
client -> DNS (what IP is "myDynDNShostname"?) -> "104.34.x.x"
then
client -> internet -> router (104.34.x.x) -> server (192.168.x.x)
即使ISP分配静态IP而不是动态IP,考虑为其创建静态主机名仍然是个好主意,因为主机名比IP地址更容易记住。
此外,我认为ISP提供IP的方式也有所不同。我的意思是:“ipconfig”显示我有192.168.x.x;但像“whatismyip.com”这样的网站向我展示了不同的地址。
这是完全正常的。 192.168.x.x
是私有LAN IP。在服务器计算机上运行ipconfig
将显示路由器已分配给计算机的IP,而不是ISP已分配的路由器的公共IP。像“whatismyip.com”这样的网站只能显示直接连接到它们的远程IP,在这种情况下是路由器的公共IP,而不是服务器的专用LAN IP:
browser (192.168.x.x) -> router (104.34.x.x) -> internet -> website
TForm1.GetIPAddress函数向我展示了192.168.x.x。
因为那是由路由器分配给该本地机器的IP,它直接连接到。
答案 1 :(得分:0)
您的朋友应该尝试连接到whatismyip.com等网站所显示的IP地址。 192.168.x.x是您家庭网络上的私有IP地址,无法从Internet直接访问。
您需要将应用程序在ISP路由器上使用的端口转发到本地IP地址才能使其正常工作。 Google&#34;端口转发&#34;开始。
请记住,您可能会从ISP收到动态IP地址,这意味着IP会定期更改。因此,您需要检查您的IP是什么,并在连接之前向您的朋友提供更新的地址。另一种方法是使用动态DNS服务,这将允许您的朋友使用域名而不是IP地址连接到您的应用程序。