http://blog.csdn.net/lailai186/article/details/8788710?utm_source=tuicool

TClientSocket和TServerSocket的数据通知使用了Windwos下的消息通知机制,造成它们只适合针对窗口的WinForm程序,因为可以得到窗口的Handle句柄,用来postmessage或者sendmessage,但对于Dll这样的不存在窗口的工程就不适应了,我做了测试:

在DLL工程中引入TClientSocket,设置HostIP,HostPort后,Active后开始send数据,然后Active设置false关闭连接,但服务端没有收到数据,server端的ClientReadr事件不能被调用。

所以考虑一下还是用Windows的API来实现标准的Socket连接,结果通讯可以得到数据了。一下是实现代码,贴出来希望对做D7Socket的DLL需求的哥们有个帮助。

Server端代码:

{*************************************************
**uSocketFasca
@note:winsock 服务程序封装类

}

unit uSocketFasca;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, WinSock,LoggerU; //定义socket传输的数据结构
type
PPACKDATA=^TPACKDATA;
TPACKDATA=record
cmd:string[];
data:string[];
id:LongInt;
end; //定义服务数据获取线程
TServerThread=class(TThread)
private
FSocket:Integer;
g_preId:Integer;
protected
procedure Execute; override;
procedure DecvDataLoop;
public
constructor Create(SockHd:Integer);
end; //定义server启动线程
TInvokerThread=class(TThread)
private
m_serversocket:Integer;
m_clientsocket:Integer;
m_serveraddr:sockaddr_in;
Client_Addr: TSockAddr;
ClientLen: Integer;
FHostIp:string;
FHostPort:Integer;
protected
procedure Execute;override;
//初始化并启动服务
procedure InitAndStartServerSocket;
//释放WInSOck
procedure WSACleanup();
procedure InitLogger();
public
constructor Create(HostIp:string;HostPort:Integer);
end; var
FLogger:TLogger; implementation {TInvokerThread}
procedure TInvokerThread.InitLogger();
begin
FLogger:=TLogger.GetLoggerInstance('uSocketFasca');
end; //初始化并启动服务socket
procedure TInvokerThread.InitAndStartServerSocket;
var
XL_WSADATA:TWSAData;
Ret:Integer;
threadFunc:TServerThread;
tm : Longint;
begin
//init winsock 2.0 libaray
Ret:=WSAStartup(MakeWord(,),XL_WSADATA);
if (<>Ret) then
begin
FLogger.Send('WSASetUp error!');
Exit;
end;
//create socket
m_serversocket:=socket(PF_INET,SOCK_STREAM,);
if INVALID_SOCKET = m_serversocket then
begin
FLogger.Send('Create socket error!');
Exit;
end;
tm:=;//非锁定模式 ;TM:=0锁定模式
ioctlsocket(m_serversocket,FIONBIO,tm);
//bind socket
m_serveraddr.sin_family:=PF_INET ;
m_serveraddr.sin_port:=htons(FHostPort);
m_serveraddr.sin_addr.S_addr:=INADDR_ANY;
Ret:=bind(m_serversocket,m_serveraddr,SizeOf(m_serveraddr));
if Ret=SOCKET_ERROR then
begin
FLogger.Send('socket bind error!');
Exit;
end;
//linsten
Ret:=listen(m_serversocket,);
if Ret=SOCKET_ERROR then
begin
FLogger.Send('listen socket error!');
Exit;
end;
m_clientsocket:=INVALID_SOCKET;
while(True) do
begin
if terminated then
begin
threadFunc.Terminate;
exit;
end;
//阻塞模式
FillChar(Client_Addr,Sizeof(Client_Addr),);
ClientLen := Sizeof(Client_Addr);
m_clientsocket:=accept(m_serversocket,@Client_Addr,@ClientLen) ;
if m_clientsocket <> INVALID_SOCKET then
begin
threadFunc:=TServerThread.Create(m_clientsocket);
end;
Application.ProcessMessages;
end;
Application.ProcessMessages;
end; procedure TInvokerThread.WSACleanup();
begin
closesocket(m_serversocket);
end; constructor TInvokerThread.Create(HostIp: string; HostPort: Integer);
begin
inherited Create(False);
FHostIp:=HostIp;
FHostPort:=HostPort;
FreeOnTerminate:=True;
InitLogger;
end; procedure TInvokerThread.Execute;
begin
inherited;
Synchronize(InitAndStartServerSocket);
if Terminated then Exit;
end; { TServerThread } constructor TServerThread.Create(SockHd: Integer);
begin
inherited Create(False);
FSocket:=SockHd;
FreeOnTerminate:=True;
g_preId:=-;
end; procedure TServerThread.DecvDataLoop;
var
Buff:TPACKDATA;
SendBuf:string[];
RET: Integer;
FdSet : TFDSet;
TimeVal : TTimeVal;
begin while(true) do
begin
if terminated then exit;
//非阻塞模式
FD_ZERO(FdSet);
FD_SET(FSocket,FdSet);
TimeVal.tv_sec:=;
TimeVal.tv_usec:=;
if (select(,@FdSet,nil,nil,@TimeVal)>) and (not terminated) then
begin
Ret:=recv(FSocket,Buff,SizeOf(Buff),);
if RET=SOCKET_ERROR then
begin
FLogger.Send('Read Error!');
Continue;
end;
if RET > then
begin
if (g_preId<>Buff.id) then begin
g_preId:=Buff.id;
FLogger.Send('Recv Cmd:'+Buff.cmd) ;
FLogger.Send('Recv Data:'+Buff.Data) ;
FLogger.Send('Recv Id:'+inttostr(Buff.id)) ;
SendBuf:='Rec OK';
send(FSocket,SendBuf,SizeOf(SendBuf),);
break; end; end;
end; //end select
end; end; procedure TServerThread.Execute;
begin
inherited;
Synchronize(DecvDataLoop);
if Terminated then Exit;
end; end. 调用逻辑: unit uMain; interface uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uSocketFasca, StdCtrls; type
TForm1 = class(TForm)
Button1: TButton;
btn1: TButton;
procedure Button1Click(Sender: TObject);
procedure btn1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction); private
{ Private declarations }
invoker:TInvokerThread;
public
{ Public declarations }
end; var
Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject);
var
HostIp,HostPort:string;
begin
HostIp:='192.168.50.1';
HostPort:='';
invoker:=TInvokerThread.Create(HostIp,StrToInt(HostPort));
end; procedure TForm1.btn1Click(Sender: TObject);
begin
showmessage('@!@');
end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
invoker.Terminate;
//TerminateThread(invoker.Handle,0); end; end.

客户端

unit uSocketLibrary;

interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, WinSock,LoggerU; type
PPACKDATA=^TPACKDATA;
TPACKDATA=record
cmd:string[];
data:string[];
id:LongInt;
end; TClient_Socket=class
private
FLogger:TLogger;
client_socket:Integer;
Fhost_port:Integer;
client_hostent:PHostEnt;
client_addr:TSockAddrIn;
psaddr:^LongInt;
saddr:LongInt;
Fhost_ip:string;
public
procedure DisconnectServer();
function ConnectionServer():Integer;
function SendData(buff:TPACKDATA): integer;
function RecvData():integer;
constructor Create(IpAddr:string;HostPort:Integer);
end;
implementation { TClient_Socket } function TClient_Socket.ConnectionServer: Integer;
var
Clt_WSADATA:TWSAData;
Ret:Integer;
begin
Ret:=WSAStartup(MakeWord(,),Clt_WSADATA);
if (<>Ret) then
begin
FLogger.Send('WSASetUp error!');
Result:=;
Exit;
end;
client_addr.sin_family:=PF_INET;
client_addr.sin_port:=htons(Fhost_port);
client_hostent:=gethostbyname(PChar(Fhost_ip)) ;
if nil=client_hostent then
begin
saddr:=inet_addr(PChar(Fhost_ip));
if -<>saddr then
client_addr.sin_addr.S_addr:=saddr;
end
else
begin
psaddr:=Pointer(client_hostent.h_addr_list^);
client_addr.sin_addr.S_addr:=psaddr^;
end;
client_socket:=socket(PF_INET,SOCK_STREAM,);
if INVALID_SOCKET = client_socket then
begin
FLogger.Send('create socket fail!');
Result:=;
exit;
end;
Ret:=connect(client_socket,client_addr,SizeOf(client_addr));
if socket_error = Ret then
begin
closesocket(client_socket);
FLogger.Send('Connect fail!');
Result:=;
exit;
end;
Result:=;
end; constructor TClient_Socket.Create(IpAddr: string; HostPort: Integer);
begin
FLogger:=TLogger.GetLoggerInstance('SocketLibaray');
Fhost_ip:=IpAddr;
Fhost_port:=HostPort;
end; procedure TClient_Socket.DisconnectServer;
begin
shutdown(client_socket,SD_SEND);
closesocket(client_socket);
end; function TClient_Socket.RecvData: integer;
var
buff:string[];
ret:integer;
begin
Result:=;
ret:=recv(client_socket,buff,SizeOf(buff),);
if (SOCKET_ERROR=ret) then
begin
FLogger.Send('Read Error!');
Result:=;
Exit;
end
else if ret> then
begin
if (buff='Rec OK') then
Result:=;
end;
end; function TClient_Socket.SendData(buff:TPACKDATA): integer;
var
//strBuf:string[254];
ret:Integer;
begin
ret:=send(client_socket,buff,SizeOf(buff),);
Result:=;
end; end. DLL工程逻辑: library PrjDLL; { Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. } uses
SysUtils,
Classes,
uSocketLibrary in 'uSocketLibrary.pas'; function ConnectServerAndSendData(IpAddr:string;RPort:string;buffer:TPACKDATA):integer;stdcall;
var
clt:TClient_Socket;
hostIp,sPort,sData:string;
hostPort:Integer;
begin
hostIp:=IpAddr;
sPort:=RPort;
//sData:=;
hostPort:=StrToInt(sPort);
clt:=TClient_Socket.Create(hostIp,hostPort);
try
if clt.ConnectionServer= then
begin
if clt.SendData(buffer)= then
begin
while(clt.RecvData=) do
begin
Result:=;
break;
end;
end;
end;
finally
clt.DisconnectServer;
clt.Free;
end;
Result:=;
end; exports ConnectServerAndSendData; {$R *.res} begin end.

好了,整个过程代码都在这了。有需要的兄弟可以贴下来试试,我是用Delphi7编译并测试通过的。希望有所帮助!

delphi socket 编程 使用多线程的更多相关文章

  1. 初涉Delphi Socket编程

    不是第一次接触socket编程了,但以前都是看别人的依葫芦画瓢,也不知道具体的原理. 新的项目,有了新的开始,同时也需要有新的认识. Delphi 中带有两套TCP Socket组件: Indy So ...

  2. Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html 一.概述 关于Socket编程的基本方法在基础篇里已经讲过,今天把 ...

  3. Delphi Socket通信及多线程编程总结

    http://cxhblog.blog.sohu.com/41930676.html 一.Socket通信: Delphi在ScktComp单元中对WinSock进行了封装,该单元提供了TAbstra ...

  4. Python学习笔记——进阶篇【第八周】———进程、线程、协程篇(Socket编程进阶&多线程、多进程)

    本节内容: 异常处理 Socket语法及相关 SocketServer实现多并发 进程.线程介绍 threading实例 线程锁.GIL.Event.信号量 生产者消费者模型 红绿灯.吃包子实例 mu ...

  5. 为什么socket编程要用到多线程

    不得不佩服计算机先驱的设计:socket编程为什么需要多线程.如果只有一个ServerSocket线程,那么如下代码: public void start() throws Exception { S ...

  6. 使用libevent进行多线程socket编程demo

    最近要对一个用libevent写的C/C++项目进行修改,要改成多线程的,故做了一些学习和研究. libevent是一个用C语言写的开源的一个库.它对socket编程里的epoll/select等功能 ...

  7. socket编程,简单多线程服务端测试程序

    socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...

  8. 多线程Java Socket编程示例

    package org.merit.test.socket; import java.io.BufferedReader; import java.io.IOException; import jav ...

  9. 多线程编程以及socket编程_Linux程序设计4chapter15

    看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建 ...

随机推荐

  1. kali linux2.0安装vega

    1.到官网下载安装包(选择版本:我这里以Linux64位为例) vega下载地址:https://subgraph.com/vega/download/ 2.解压到指定目录: unzip VegaBu ...

  2. python基础-装饰器,生成器和迭代器

    学习内容 1.装饰器 2.生成器 3.迭代器 4.软件目录结构规范 一:装饰器(decorator) 1.装饰器定义:本质就是函数,用来装饰其他函数,即为其他函数添加附加功能. 2.装饰器原则:1)不 ...

  3. Kafka 集群配置SASL+ACL

    一.简介 在Kafka0.9版本之前,Kafka集群时没有安全机制的.Kafka Client应用可以通过连接Zookeeper地址,例如zk1:2181:zk2:2181,zk3:2181等.来获取 ...

  4. python包管理之Pip安装及使用

    Python有两个著名的包管理工具easy_install.py和pip.在Python2.7的安装包中,easy_install.py是默认安装的,而pip需要我们手动安装. pip可以运行在Uni ...

  5. interface关键字定义接口

    package interface0; public interface InterfaceTest { /* * 接口的定义,使用interface关键字定义接口 */ public interfa ...

  6. 更换网页tab标题图标

    在首页HTML文件中,加入link命令,<link>是放在<head>与</head>之间 例如下面这样: <HEAD><link rel = & ...

  7. SqlServer 递归查询树

    递归关于进行树形结构的查询: 一:简单的树形结构代码. -- with一个临时表(括号中是你要查询的列名) with temp(ID,PID,Name,curLevel) as ( --1:初始查询( ...

  8. shell学习(三)

    libvirt用于管理KVM本身的工具 virt-install用于安装虚拟机需要的安装包,安装虚拟机 virt-mananger:管理创建删除虚拟机的工具 ---恢复内容开始--- 1    gre ...

  9. spark web ui中的skipped的含义

    顾名思义,跳出的意思啦. 例如如图: skipped的stages代表是已经执行过了.所以不需要再执行了. 如何,你有一个 testRdd.然后先做 testRdd.Filter("xxx& ...

  10. [Java/Python] java调用python脚本问题记录

    Java调用Python的的两种方式 1.Runtime private static String call_python(String input_argv) { String python_py ...