P
phyyun
Unregistered / Unconfirmed
GUEST, unregistred user!
目前只能实现,server端也就是接收端需要有独立的IP。这样的互传我已经实现了。
我想实现象QQ那样。比如接收方在局域网内一台机器a上,在7777端口listen,通过主机b连到internet。c机也是通过internet想连a机,假设c机已经知道目标ip,是b机的,也就网关的,那么怎么映射到A机呢?
我不是用udp连接的。使用clientsocket,serversocket实现的。
如果需要建立一个独立IP的服务器,象QQ服务器一样,存放A,C机连接到服务器的ip和端口。我想a机出去,服务器应该是存放的是b机的端口吧。但具体如何实现,请帮忙提供一下思路,能够有源码更好。
200分不多。如果有思路,我会另外发贴给分。有源码就给500。
server端.pas文件如下:
×××××××××××××××××××××××××××××××××××××
unit server;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
SaveDialog1: TSaveDialog;
ProgressBar1: TProgressBar;
Button1: TButton;
Edit3: TEdit;
Label3: TLabel;
Label1: TLabel;
StatusBar1: TStatusBar;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure SaveDialog1CanClose(Sender: TObject; var CanClose: Boolean);
procedure Button1Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Button2Click(Sender: TObject);
procedure ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
private
{ Private declarations }
public
end;
toptions = (load, listen, api);
tinfo = (fname, size, path);
var
Form1: TForm1;
opt, loadopt: toptions;
info: tinfo;
// m1:tmemorystream;
RecevFstream: TFileStream;
filesize: longint; //文件长度;
fullfilesize: longint;
filename, filepath: string;
suspend: boolean = false;
const
maxsize = 2048;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
//m1:=tmemorystream.Create; //创建流对象
{ serversocket1.port:=7777;
serversocket1.Open;
opt:=listen; }
Button1Click(nil);
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var tem: string;
len: longint; //包长度
buffer: array[0..10000] of byte; //设置接收缓冲区
buf: array[1..maxsize] of byte; //以2k大小为一个传送单位,大了可能出错
begin
if suspend then
begin
Socket.SendText('suspend');
try
RecevFstream.Free;
RecevFstream := nil;
except
end;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
suspend := false;
exit;
end;
{ tem := Socket.ReceiveText;
if tem = 'suspend' then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar2.Position := 0;
StatusBar2.Panels[1].Text := '空闲';
exit;
end;
}
case opt of //主循环
listen: //监听状态 (1级)
begin
tem := Socket.ReceiveText;
if tem = 'send' then
begin
if messagedlg('有新文件传来,要接收吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
begin
socket.SendText('getsize'); opt := load; loadopt := listen; info := size;
end
else begin
socket.SendText('refuse');
exit;
end;
end; //改变状态
end;
load: //接收流 (1级)
begin
case loadopt of
listen: //准备接收(2级)
begin
tem := Socket.ReceiveText;
case info of //准备接收的数据 (3级)
size: begin
info := fname; //改变状态
filesize := strtoint(tem);
fullfilesize := filesize;
socket.SendText('getname');
StatusBar1.Panels[1].Text := '获取文件名';
end;
{ path: begin
info:=fname; //改变状态
filepath:=tem;
socket.SendText('getname');
end;}
fname: begin
info := size; loadopt := load; //改变状态
filename := tem;
SaveDialog1.FileName := filename;
socket.SendText('getdata');
StatusBar1.Panels[1].Text := '数据传送开始';
end;
end;
end;
load: //接收中(2级)
begin
{ len:=socket.ReceiveLength; //读出包长度
socket.ReceiveBuf(buffer,len); //接收数据包并读入缓冲区内
m1.write(buffer,len); //追加入 流M 中
if m1.Size>=filesize then //完成了流M 的传送
begin
m1.Position:=0;
m1.SaveToFile(filename);
//copyfile(pchar(filename),pchar(filepath+filename),true);
opt:=listen; //开始重置状态
loadopt:=listen;
info:=size;
tem:='';
Messagedlg('传送结束', mtinformation, [mbok], 0);
socket.SendText('loadfileok');
end; }
if RecevFstream = nil then
begin
// tem:=socket.ReceiveText;
// len:=socket.ReceiveLength;
SaveDialog1.FileName := FileName;
if not SaveDialog1.Execute then
begin
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
StatusBar1.Panels[1].Text := '空闲';
socket.SendText('refuse');
exit;
end;
try
FileName := SaveDialog1.FileName;
RecevFstream := TFileStream.Create(FileName, fmCreate);
except
Messagedlg('文件写入失败', mtinformation, [mbok], 0);
exit;
end;
ProgressBar1.Max := filesize;
ProgressBar1.Position := 0;
// Socket.SendText('getdata');
end;
try
if maxsize < filesize then
begin
len:=socket.ReceiveLength; //读出包长度
if len < 10 then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
exit;
end;
Socket.ReceiveBuf(buf, maxsize);
RecevFstream.WriteBuffer(buf, maxsize);
filesize := filesize - maxsize;
socket.SendText('getdata');
ProgressBar1.StepBy(maxsize);
StatusBar1.Panels[1].Text := '数据传送中...' + '文件总长度' + inttostr(fullfilesize) + '字节,剩余' + inttostr(filesize) + '字节';
end
else
begin
len:=socket.ReceiveLength; //读出包长度
if len < 10 then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
exit;
end;
socket.ReceiveBuf(buf, filesize);
RecevFstream.WriteBuffer(Buf, filesize);
RecevFstream.Free;
RecevFstream := nil;
ProgressBar1.Position := ProgressBar1.Max;
StatusBar1.Panels[1].Text := '数据传送完毕';
Messagedlg('传送结束', mtinformation, [mbok], 0);
socket.SendText('loadfileok');
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
end;
except
Messagedlg('数据包写入失败', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
exit;
end;
end;
end; // of case loadopt
end; //接收流over
api: //执行各种命令 (1级)
begin
end;
end; //of case opt
end;
procedure TForm1.SaveDialog1CanClose(Sender: TObject;
var CanClose: Boolean);
begin
if FileExists(SaveDialog1.FileName) then
begin
if Messagedlg('目标文件已存在,覆盖吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
DeleteFile(SaveDialog1.FileName)
else
CanClose := false;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
Messagedlg('上次传送还未结束', mtinformation, [mbok], 0);
exit;
end;
try
serversocket1.Close;
serversocket1.port := strtoint(edit3.text);
serversocket1.Open;
opt := listen;
StatusBar1.Panels[0].Text := '已上线';
StatusBar1.Panels[1].Text := '空闲';
except
StatusBar1.Panels[0].Text := '离线';
StatusBar1.Panels[1].Text := '';
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
if messagedlg('文件传送还未结束,确认退出吗?', mtconfirmation, [mbyes, mbno], 0) = mrno then
begin
CanClose := false;
abort;
end;
suspend := true;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
if messagedlg('文件传送还未结束,确认中止吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
begin
suspend := true;
{ ServerSocket1.Close;
try
RecevFstream.Free;
RecevFstream:=nil;
except
end;
opt:=listen; //开始重置状态
loadopt:=listen;
info:=size;
ProgressBar1.Position:=0;
StatusBar1.Panels[1].Text:='空闲';
ServerSocket1.Open; }
end;
end;
end;
procedure TForm1.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
StatusBar1.Panels[0].Text := '已上线';
StatusBar1.Panels[1].Text := '传送失败';
errorcode := 0;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
ProgressBar1.Position := 0;
if (RecevFstream <> nil) then
begin
RecevFstream.Free;
RecevFstream := nil;
end;
end;
end.
××××××××××××××××××××××××××××××
dfm文件如下:
object Form1: TForm1
Left = 289
Top = 233
Width = 430
Height = 125
Caption = 'server'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poDesktopCenter
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label3: TLabel
Left = 16
Top = 16
Width = 18
Height = 13
Caption = 'port'
end
object Label1: TLabel
Left = 0
Top = 40
Width = 48
Height = 13
Caption = '传送进度'
end
object ProgressBar1: TProgressBar
Left = 0
Top = 56
Width = 417
Height = 16
Min = 0
Max = 100
TabOrder = 0
end
object Button1: TButton
Left = 176
Top = 8
Width = 75
Height = 25
Caption = 'listen'
TabOrder = 1
OnClick = Button1Click
end
object Edit3: TEdit
Left = 40
Top = 11
Width = 121
Height = 21
TabOrder = 2
Text = '7777'
end
object StatusBar1: TStatusBar
Left = 0
Top = 79
Width = 422
Height = 19
Panels = <
item
Width = 50
end
item
Width = 300
end>
SimplePanel = False
end
object Button2: TButton
Left = 256
Top = 8
Width = 73
Height = 25
Caption = 'stop'
TabOrder = 4
OnClick = Button2Click
end
object ServerSocket1: TServerSocket
Active = False
Port = 0
ServerType = stNonBlocking
OnClientRead = ServerSocket1ClientRead
OnClientError = ServerSocket1ClientError
Left = 152
Top = 24
end
object SaveDialog1: TSaveDialog
OnCanClose = SaveDialog1CanClose
Left = 216
Top = 24
end
end
我想实现象QQ那样。比如接收方在局域网内一台机器a上,在7777端口listen,通过主机b连到internet。c机也是通过internet想连a机,假设c机已经知道目标ip,是b机的,也就网关的,那么怎么映射到A机呢?
我不是用udp连接的。使用clientsocket,serversocket实现的。
如果需要建立一个独立IP的服务器,象QQ服务器一样,存放A,C机连接到服务器的ip和端口。我想a机出去,服务器应该是存放的是b机的端口吧。但具体如何实现,请帮忙提供一下思路,能够有源码更好。
200分不多。如果有思路,我会另外发贴给分。有源码就给500。
server端.pas文件如下:
×××××××××××××××××××××××××××××××××××××
unit server;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
SaveDialog1: TSaveDialog;
ProgressBar1: TProgressBar;
Button1: TButton;
Edit3: TEdit;
Label3: TLabel;
Label1: TLabel;
StatusBar1: TStatusBar;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure SaveDialog1CanClose(Sender: TObject; var CanClose: Boolean);
procedure Button1Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Button2Click(Sender: TObject);
procedure ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
private
{ Private declarations }
public
end;
toptions = (load, listen, api);
tinfo = (fname, size, path);
var
Form1: TForm1;
opt, loadopt: toptions;
info: tinfo;
// m1:tmemorystream;
RecevFstream: TFileStream;
filesize: longint; //文件长度;
fullfilesize: longint;
filename, filepath: string;
suspend: boolean = false;
const
maxsize = 2048;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
//m1:=tmemorystream.Create; //创建流对象
{ serversocket1.port:=7777;
serversocket1.Open;
opt:=listen; }
Button1Click(nil);
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var tem: string;
len: longint; //包长度
buffer: array[0..10000] of byte; //设置接收缓冲区
buf: array[1..maxsize] of byte; //以2k大小为一个传送单位,大了可能出错
begin
if suspend then
begin
Socket.SendText('suspend');
try
RecevFstream.Free;
RecevFstream := nil;
except
end;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
suspend := false;
exit;
end;
{ tem := Socket.ReceiveText;
if tem = 'suspend' then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar2.Position := 0;
StatusBar2.Panels[1].Text := '空闲';
exit;
end;
}
case opt of //主循环
listen: //监听状态 (1级)
begin
tem := Socket.ReceiveText;
if tem = 'send' then
begin
if messagedlg('有新文件传来,要接收吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
begin
socket.SendText('getsize'); opt := load; loadopt := listen; info := size;
end
else begin
socket.SendText('refuse');
exit;
end;
end; //改变状态
end;
load: //接收流 (1级)
begin
case loadopt of
listen: //准备接收(2级)
begin
tem := Socket.ReceiveText;
case info of //准备接收的数据 (3级)
size: begin
info := fname; //改变状态
filesize := strtoint(tem);
fullfilesize := filesize;
socket.SendText('getname');
StatusBar1.Panels[1].Text := '获取文件名';
end;
{ path: begin
info:=fname; //改变状态
filepath:=tem;
socket.SendText('getname');
end;}
fname: begin
info := size; loadopt := load; //改变状态
filename := tem;
SaveDialog1.FileName := filename;
socket.SendText('getdata');
StatusBar1.Panels[1].Text := '数据传送开始';
end;
end;
end;
load: //接收中(2级)
begin
{ len:=socket.ReceiveLength; //读出包长度
socket.ReceiveBuf(buffer,len); //接收数据包并读入缓冲区内
m1.write(buffer,len); //追加入 流M 中
if m1.Size>=filesize then //完成了流M 的传送
begin
m1.Position:=0;
m1.SaveToFile(filename);
//copyfile(pchar(filename),pchar(filepath+filename),true);
opt:=listen; //开始重置状态
loadopt:=listen;
info:=size;
tem:='';
Messagedlg('传送结束', mtinformation, [mbok], 0);
socket.SendText('loadfileok');
end; }
if RecevFstream = nil then
begin
// tem:=socket.ReceiveText;
// len:=socket.ReceiveLength;
SaveDialog1.FileName := FileName;
if not SaveDialog1.Execute then
begin
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
StatusBar1.Panels[1].Text := '空闲';
socket.SendText('refuse');
exit;
end;
try
FileName := SaveDialog1.FileName;
RecevFstream := TFileStream.Create(FileName, fmCreate);
except
Messagedlg('文件写入失败', mtinformation, [mbok], 0);
exit;
end;
ProgressBar1.Max := filesize;
ProgressBar1.Position := 0;
// Socket.SendText('getdata');
end;
try
if maxsize < filesize then
begin
len:=socket.ReceiveLength; //读出包长度
if len < 10 then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
exit;
end;
Socket.ReceiveBuf(buf, maxsize);
RecevFstream.WriteBuffer(buf, maxsize);
filesize := filesize - maxsize;
socket.SendText('getdata');
ProgressBar1.StepBy(maxsize);
StatusBar1.Panels[1].Text := '数据传送中...' + '文件总长度' + inttostr(fullfilesize) + '字节,剩余' + inttostr(filesize) + '字节';
end
else
begin
len:=socket.ReceiveLength; //读出包长度
if len < 10 then
begin
Messagedlg('对方中止传送', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
exit;
end;
socket.ReceiveBuf(buf, filesize);
RecevFstream.WriteBuffer(Buf, filesize);
RecevFstream.Free;
RecevFstream := nil;
ProgressBar1.Position := ProgressBar1.Max;
StatusBar1.Panels[1].Text := '数据传送完毕';
Messagedlg('传送结束', mtinformation, [mbok], 0);
socket.SendText('loadfileok');
opt := listen; //开始重置状态
loadopt := listen;
info := size;
tem := '';
ProgressBar1.Position := 0;
StatusBar1.Panels[1].Text := '空闲';
end;
except
Messagedlg('数据包写入失败', mtinformation, [mbok], 0);
RecevFstream.Free;
RecevFstream := nil;
exit;
end;
end;
end; // of case loadopt
end; //接收流over
api: //执行各种命令 (1级)
begin
end;
end; //of case opt
end;
procedure TForm1.SaveDialog1CanClose(Sender: TObject;
var CanClose: Boolean);
begin
if FileExists(SaveDialog1.FileName) then
begin
if Messagedlg('目标文件已存在,覆盖吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
DeleteFile(SaveDialog1.FileName)
else
CanClose := false;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
Messagedlg('上次传送还未结束', mtinformation, [mbok], 0);
exit;
end;
try
serversocket1.Close;
serversocket1.port := strtoint(edit3.text);
serversocket1.Open;
opt := listen;
StatusBar1.Panels[0].Text := '已上线';
StatusBar1.Panels[1].Text := '空闲';
except
StatusBar1.Panels[0].Text := '离线';
StatusBar1.Panels[1].Text := '';
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
if messagedlg('文件传送还未结束,确认退出吗?', mtconfirmation, [mbyes, mbno], 0) = mrno then
begin
CanClose := false;
abort;
end;
suspend := true;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if serversocket1.Active and (RecevFstream <> nil) then
begin
if messagedlg('文件传送还未结束,确认中止吗?', mtconfirmation, [mbyes, mbno], 0) = mryes then
begin
suspend := true;
{ ServerSocket1.Close;
try
RecevFstream.Free;
RecevFstream:=nil;
except
end;
opt:=listen; //开始重置状态
loadopt:=listen;
info:=size;
ProgressBar1.Position:=0;
StatusBar1.Panels[1].Text:='空闲';
ServerSocket1.Open; }
end;
end;
end;
procedure TForm1.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
StatusBar1.Panels[0].Text := '已上线';
StatusBar1.Panels[1].Text := '传送失败';
errorcode := 0;
opt := listen; //开始重置状态
loadopt := listen;
info := size;
ProgressBar1.Position := 0;
if (RecevFstream <> nil) then
begin
RecevFstream.Free;
RecevFstream := nil;
end;
end;
end.
××××××××××××××××××××××××××××××
dfm文件如下:
object Form1: TForm1
Left = 289
Top = 233
Width = 430
Height = 125
Caption = 'server'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poDesktopCenter
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label3: TLabel
Left = 16
Top = 16
Width = 18
Height = 13
Caption = 'port'
end
object Label1: TLabel
Left = 0
Top = 40
Width = 48
Height = 13
Caption = '传送进度'
end
object ProgressBar1: TProgressBar
Left = 0
Top = 56
Width = 417
Height = 16
Min = 0
Max = 100
TabOrder = 0
end
object Button1: TButton
Left = 176
Top = 8
Width = 75
Height = 25
Caption = 'listen'
TabOrder = 1
OnClick = Button1Click
end
object Edit3: TEdit
Left = 40
Top = 11
Width = 121
Height = 21
TabOrder = 2
Text = '7777'
end
object StatusBar1: TStatusBar
Left = 0
Top = 79
Width = 422
Height = 19
Panels = <
item
Width = 50
end
item
Width = 300
end>
SimplePanel = False
end
object Button2: TButton
Left = 256
Top = 8
Width = 73
Height = 25
Caption = 'stop'
TabOrder = 4
OnClick = Button2Click
end
object ServerSocket1: TServerSocket
Active = False
Port = 0
ServerType = stNonBlocking
OnClientRead = ServerSocket1ClientRead
OnClientError = ServerSocket1ClientError
Left = 152
Top = 24
end
object SaveDialog1: TSaveDialog
OnCanClose = SaveDialog1CanClose
Left = 216
Top = 24
end
end