编制*.dll文件,实现将字符串上传到一服务器。(大概应用socket类吧) ( 积分: 200 )

  • 主题发起人 主题发起人 zikao419
  • 开始时间 开始时间
Z

zikao419

Unregistered / Unconfirmed
GUEST, unregistred user!
思路:客户端在dll文件中,动态创建socket组件,然后将要传的串传到一服务器,处理完以后,由服务器传回结果,客户端接受。

只要能实现,分数不是问题。
 
去2ccc.com上搜Indy,很简单,然后把你的逻辑封装成dll就ok了
 
控件使用不是问题,主要是如何在动态连接库中创建,监听等封装。
 
这个简单。我现在做的就是用的这个原理。当然要和中间层结合使用。
声明一个类,
uses
ShareMem, SysUtils, Classes, DBClient, SConnect, IniFiles, SysUnit,Variants,
DB, Forms, Windows, uSysInfo;

type
TSrvInfo = class(TComponent)
private
FServer: string;
FPort: string;
FServer_Name: string;
procedure Init;
procedure GetServerInfo;
public
SocketCon: TSocketConnection;
cdsMenu: TClientDataSet;
cdsTmp: TClientDataSet;
UserInfo: TUserInfo;
SysInfo: TSysInfo;
function Reconnect: boolean;
function GetServerDate: TDateTime;
function GetUserInfo(UserName: WideString): TUserInfo;
function GetMenuDll(MenuName: string): TMenuDll;
function GetMenuData(UserID,UserPwd, ARegister: WideString; var AMsg: WideString): boolean;
function GetFieldValue(ASource: TClientDataSet; AField: string): string;

function IsValidateUser(HardDiskID, MACID, User,
Pwd: string; var AMsg: WideString): Integer;
function GetBillInNum(ABillName: string): string;
function GetBillOutNum(ABillName: string): string;
function AppDir: string;
function Connected: boolean;
procedure Close;
procedure Open;

property Server: string read FServer write FServer;
property Port: string read FPort write FPort;
property ServerName: string read FServer_Name write FServer_Name;

constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
把SocketConnection作为它的一个成员。
然后利用中间层提供的方法进行读写数据,不管是字符串,还是数据库。
例如:
function TSrvInfo.GetBillInNum(ABillName: string): string;
var
InNum: WideString;
begin
Result := '';
if Reconnect then
if SocketCon.AppServer.GetInNumber(WideString(ABillName), InNum) then
Result := InNum;
end;
利用
SocketCon.AppServer后面的服务器提供的方法即可。
 
to happycyp:
想法是一样的,我也是服务器端写一个中间层对数据进行处理(读写数据库)但是,客户端我实在是不会搞定了“如何在动态连接库中创建,监听等封装。”
你可不可以帮我写一个简单的收发例子。
小弟不胜感谢(我做了好几天了实在没有办法了)
 
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,WinSock,StdCtrls;

const
WM_SOCK = WM_USER + 1; //自定义windows消息
TCP_PORT = 5432; //设定TCP端口号

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
HasConnected, IsServer: boolean;
CliSocket, SvrSocket: integer;
SvrAddrIn, CliAddrIn:TSockAddrIn;
procedure InitSocket;
procedure SockConnect;
procedure ReadData(var Message: TMessage); message WM_SOCK;
procedure SendData(Content: string);

public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.InitSocket;
var
wsadata: TWsadata;
err{, optval}: integer;
begin

WSAStartup($0101,WSAData);

CliSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);
SvrSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);

if (CliSocket = INVALID_SOCKET) or (SvrSocket = INVALID_SOCKET) then
begin
ShowMessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(CliSocket);
exit;
end;

SvrAddrIn.sin_addr.s_addr:= INADDR_ANY;
SvrAddrIn.sin_family := AF_INET;
SvrAddrIn.sin_port :=htons(TCP_PORT);
Bind(SvrSocket, SvrAddrIn, sizeof(SvrAddrIn));

err := Listen(SvrSocket,5);
if err<>0 then ShowMessage('Listen error.');

//绑定消息映射
[red]1[/red] WSAAsyncSelect(SvrSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);
[red]1[/red] WSAAsyncSelect(CliSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);
end;

procedure TForm1.SockConnect;
var
err: integer;
begin

CliAddrIn.sin_addr.s_addr:=inet_addr(PChar(Edit1.Text));
CliAddrIn.sin_family := AF_INET;
CliAddrIn.sin_port :=htons(TCP_PORT);
repeat
err:=connect(CliSocket,CliAddrIn, SizeOf(CliAddrIn));
if err = -1 then
begin
HasConnected := false;
break;
end
else
begin
HasConnected := true;
IsServer := false;
end;
until err=0;
end;

procedure TForm1.ReadData(var Message: TMessage);
var
Event: word;
Buf:array[0..1023] of char;
AddrLen, DataLen: integer;
begin
AddrLen := sizeof(SvrAddrIn);
[red]2[/red] Event := WSAGetSelectEvent(Message.LParam);

case Event of
FD_CONNECT:
begin
ListBox1.Items.Add('connect');
HasConnected := true;
end;
FD_ACCEPT:
begin
IsServer := true;
HasConnected := true;
ListBox1.Items.Add('accept');
CliSocket := Accept(SvrSocket,@SvrAddrIn,@AddrLen);
end;
FD_READ:
begin
DataLen := Recv(CliSocket,Buf,1024,0);
buf[DataLen] := #0;
ListBox1.Items.Add(Buf);
end;
FD_WRITE:
begin
ListBox1.Items.Add('write');
end;
FD_OOB:
begin
ListBox1.Items.Add('FD_OOB');
end;
FD_CLOSE:
begin
HasConnected := false;
ListBox1.Items.Add('close');
end;
end; //end of case
end;

procedure TForm1.SendData(Content: string);
begin
Send(CliSocket,Content[1],length(Content),0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//202.104.32.230
if (not IsServer) and (not HasConnected) then
SockConnect;
SendData('hello, world');
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseSocket(SvrSocket);
CloseSocket(CliSocket);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
HasConnected := false;
IsServer := false;
InitSocket;
end;

end.

这个程序已经做成了,但是在做成dll的时候出现如下问题:(帮我一下)

[red]1[/red]WSAAsyncSelect(SvrSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE); 这里的Handle是窗体句柄,我如何传递(这个程序没在做成dll文件时功能已经实现)
[red]2[/red] Event := WSAGetSelectEvent(Message.LParam);这里的又该如何处理?
 
WSAAsyncSelect这种异步i/o模型是基于窗口消息的
你的dll如果没有窗口也就没有窗口回调例程,
所以你不能使用这种基于消息的模型
可以使用另一个有用的异步I/O模型WSAEventSelect

该模型最主要的差别在于网络事件会投
递至一个事件对象句柄,而非投递至一个窗口例程

这个你可参考一下<windows网络编程> 这本书
 
我认为用 ICS 比较好。

用 COM DLL 方式,生成一个对象。加入事件
 
在dll里和在exe里实现socket没有任何区别
你可以在dll里边提供一个函数函数的参数是服务器端IP和端口 函数所做的就是
连接服务端 ,发送命令,发送数据,接收返回。
你可以使用一个TidtcpClient
var
CLient:TidtcpClient;
begin
//创建并且连接服务端
//发送一个命令让服务端准备接收字符串
S='123425t54235'; //要发送的字符串
Client.Write(s);
Client.readint;//读取服务端回传的结果
end;
 
基于窗口消息也不怕,加入Classes单元,用AllocateWND建一个隐藏窗口,或自己用CreateWindowEX建一个.
 
EXE + Dll + MIDAS
你这是三层架构设计方案,也可以查相关的三层架构设计方面的书籍。
 
我认为这段程序不错,可惜调试通不过,谁可以帮我调试一下这段程序?

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,StdCtrls, Winsock2, Global, SyncObjs;

type
TForm1 = class(TForm)
btnStartup: TButton;
btnCleanup: TButton;
Edit: TEdit;
btnClose: TButton;
cmbuserid: TComboBox;
Label1: TLabel;
Memo: TMemo;
Button1: TButton;
procedure btnStartupClick(Sender: TObject);
procedure btnCloseClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TServerThread = class(TThread)
public
procedure execute; override;
end;

var
Form1: TForm1;
EventTotal: DWord;
SocketArray: array [0..wsa_maximum_wait_events-1] of TSocket;
EventArray: array [0..wsa_maximum_wait_events-1] of WSAEvent;
NewEvent: TWSAEvent;
NetWorkEvents: PWSANetWorkEvents;
AcceptSocket, ListenSocket: TSocket;
buf: TBuf;

implementation

{$R *.dfm}

procedure TForm1.btnStartupClick(Sender: TObject);
var
wsaData: TWSAData;
ServerAddr: TSockAddrIn;
begin
EventTotal := 0;

Memo.Lines.add('Startup...');
WSAStartup(MakeWord(2,2), wsaData); //启动Winsock

Memo.Lines.Add('socket...');
ListenSocket := socket(AF_INET, Sock_Stream, IPProto_TCP); //建立监听socket

Memo.Lines.Add('bind...');
ServerAddr.sin_family := AF_INET;
ServerAddr.sin_port := htons(port);
ServerAddr.sin_addr.S_addr := htonl(INADDR_ANY);
bind(ListenSocket, @ServerAddr, SizeOf(ServerAddr); //绑定

NewEvent := WSACreateEvent(); //建立监听套接字事件
//选择要响应的事件消息(开始只响应接受消息,read和write消息在响应accept之后再select)
WSAEventSelect(ListenSocket, NewEvent, fd_accept or fd_close);

Memo.Lines.Add('listen...');
listen(ListenSocket, 5);

SocketArray[EventTotal] := ListenSocket; //关联监听,以便响应事件
EventArray[EventTotal] := NewEvent;
inc(EventTotal);

new(NetWorkEvents);

TServerThread.create(false);
end;

procedure TForm1.btnCloseClick(Sender: TObject);
begin
close;
end;

{ TServerThread }

procedure TServerThread.execute;
var
index, i: DWord;
ClientAddr: PSockAddrIn;
AddrLen: PInteger;
begin
new(ClientAddr);
new(AddrLen);

while not Terminated do
begin

//等候所有套接字上的网络事件。
index := WSAWaitForMultipleEvents(EventTotal, @EventArray, false, wsa_infinite, false);
dec(index, wsa_wait_event_0);

//遍历所有事件,查看被传信的事件是否多于一个
for i := index to EventTotal - 1 do
begin
index := WSAWaitForMultipleEvents(1, @EventArray, true, 1000, false);

if (index = wsa_wait_failed) or (index = wsa_wait_timeout) then
continue
else
begin
index := i;

//枚举发生的事件
WSAEnumNetWorkEvents(SocketArray[index], EventArray[index], NetWorkEvents);

//检查fd_accept消息
if NetworkEvents.lNetworkEvents = fd_accept then
begin
if NetworkEvents.iErrorCode[fd_accept_bit] <> 0 then //iErrorCode的错误代码在帮助中详细描述
begin
MainForm.memo.Lines.Add(format('fd_accept failed with error %d', [NetworkEvents.iErrorCode[fd_accept_bit]]));
break;
end;

//接受一个新连接,并将它添加到套接字及事件列表中
//注意:有时候accept会返回一个很大的数值(正常数值应该是从140左右开始的),
//但系统并不报错,而实际上返回AcceptSocket是无效的socket
AcceptSocket := Accept(SocketArray[index], ClientAddr^, AddrLen^);

//由于WSAWaitForMultipleEvents函数最多只能处理64个事件对象,故关闭接受套接字
if EventTotal > wsa_maximum_wait_events then
begin
MainForm.memo.Lines.Add('Too many connections');
CloseSocket(AcceptSocket);
break;
end;

NewEvent := WSACreateEvent(); //建立接收和发送套接字事件对象

//为刚才接受建立的Socket选择要响应的事件
WsaEventSelect(AcceptSocket, NewEvent, fd_read or fd_write or fd_close);

//把接受的socket存到数组中
EventArray[EventTotal] := NewEvent;
SocketArray[EventTotal] := AcceptSocket;

inc(Eventtotal);
MainForm.memo.Lines.Add(format('SocketHandle %d connected', [AcceptSocket]));

end;

//处理fd_read通知
if NetworkEvents.lNetworkEvents = fd_read then
begin

if NetworkEvents.iErrorCode[fd_read_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_read failed with error %d', [NetworkEvents.iErrorCode[fd_read_bit]]));
break;
end;

if recv(SocketArray[index - wsa_wait_event_0], buf, bufsize, 0) = socket_error then //从套接字读入数据
raise exception.Create(IntToStr(GetLastError))
else
begin
MainForm.Memo.Lines.Add('[收到消息]' + buf.Msg);
if Send(SocketArray[buf.DestID + 1], buf, bufsize, 0) = socket_error then //转发
raise exception.Create(IntToStr(GetLastError))
else
MainForm.Memo.Lines.Add('[转发消息]' + buf.Msg);
end;

end;

if NetworkEvents.lNetworkEvents = fd_write then
begin

if NetworkEvents.iErrorCode[fd_write_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_write failed with error %d', [NetworkEvents.iErrorCode[fd_write_bit]]));
break;
end;

buf.DestID := 0;
buf.Msg := 'Hello!Welcome to Server!';
buf.MsgType := stMsg;
buf.SourceID := 0;
send(SocketArray[index - wsa_wait_event_0], buf, bufsize, 0);

end;

//处理关闭事件
if NetworkEvents.lNetworkEvents = fd_close then
begin

if NetworkEvents.iErrorCode[fd_close_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_close failed with error %d', [NetworkEvents.iErrorCode[fd_close_bit]]));
break;
end;

CloseSocket(SocketArray[index]);
end;

end;
end; //for

end; //while

dispose(ClientAddr);
dispose(AddrLen);
end;


procedure TForm1.Button1Click(Sender: TObject);
var
buf: TBuf;
begin
if cmbUserID.ItemIndex = -1 then
cmbUserID.ItemIndex := 0;
if SocketArray[cmbUserID.ItemIndex] = 0 then
memo.Lines.Add(IntToStr(cmbUserID.ItemIndex) + ' is nil');
buf.DestID := 0;
buf.Msg := edit.Text;
buf.MsgType := stMsg;
buf.SourceID := -1;

if Send(SocketArray[cmbUserID.ItemIndex + 1], buf, bufsize, 0) = socket_error then
raise exception.Create(IntToStr(GetLastError))
else
memo.Lines.Add('[发送到' + IntToStr(cmbUserID.ItemIndex) + ']' + edit.Text);
end;

end.
 
后退
顶部