⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 echoserver.dpr

📁 TCPServer(IOCPServer) Socket 大容量网络服务器解决方案 大容量网络服务器解决方案
💻 DPR
字号:
program EchoServer;

{$APPTYPE CONSOLE}

uses
  SysUtils, windows;

function JSockStart(ThreadID: Integer; Addr: Pchar; Port: Smallint; KeepAlive: Integer; SameIpCount: Integer; pOnJSockConnect: Pointer; pOnJSockReceive: Pointer; pOnJSockSendComplete: Pointer; pOnJSockDisconnect: Pointer; pOnJSockError: Pointer): Integer; stdcall; external 'tcpsrv.dll';

function JSockWork(ThreadID: Integer; TimeOut: Integer): Integer; stdcall; external 'tcpsrv.dll';

function JSockSend(ThreadID: Integer; CliID: Integer; Data: Pchar; Len: Integer; NonBlocking: Integer): Integer; stdcall; external 'tcpsrv.dll';

function JSockDisconnect(ThreadID: Integer; CliID: Integer): Integer; stdcall; external 'tcpsrv.dll';

function JSockStop(ThreadID: Integer): Integer; stdcall; external 'tcpsrv.dll';

var
  OnJSockConnectCount: Integer;
  OnJSockReceiveCount: Integer;
  OnJSockSendCount: Integer;
  OnJSockSendCompleteCount: Integer;
  OnJSockDisconnectCount: Integer;
  OnJSockErrorCount1, OnJSockErrorCount2: Integer;
  //限制,最多只能保持65407客户端长连接,一次最多只能发送和接收576个字节的数据
procedure pOnJSockConnect(ThreadID: Integer; CliID: Integer; IIP: Integer) stdcall;
begin
  {当有客户端连接时触发该事件;
  ThreadID线程序号,主要用户解决多线程共享资源访问问题,这个需要由JSockWork的ThreadID决定
  比如两个线程同时调用JSockWork参数ThreadID分别是1和2,这样这里的ThreadID可能是1或2,1标示第一个线程2标示第二个线程
  CliID是连接的编号,这个号码是0-79999的一个数字,已存在的连接不会有重复
  IIP是客户端的ip地址,可以用函数inet_ntoa转换成字符串ip
  }
    //JSockDisconnect(ThreadID, CliID); 断开当前连接
  InterlockedIncrement(OnJSockConnectCount);
end;

procedure pOnJSockReceive(ThreadID: Integer; CliID: Integer; IIP: Integer; Data: Pchar; Len: Integer) stdcall;
begin
  {当收到客户端数据时触发该事件;
  ThreadID线程序号,主要用户解决多线程共享资源访问问题,这个需要由JSockWork的ThreadID决定
  比如两个线程同时调用JSockWork参数ThreadID分别是1和2,这样这里的ThreadID可能是1或2,1标示第一个线程2标示第二个线程
  CliID是连接的编号,这个号码是0-79999的一个数字,已存在的连接不会有重复
  IIP是客户端的ip地址,可以用函数inet_ntoa转换成字符串ip
  Data是收到的数据内容
  Len是收到的数据长度
  }
  if JSockSend(ThreadID, CliID, Data, Len, 1) > 0 then
    InterlockedIncrement(OnJSockSendCount);
  {发送数据给连接编号是CliID的客户端;最后一个参数0表示阻塞模式发送,此时不回触发pOnJSockSendComplete事件;
  最后一个参数是1表示异步发送,会触发事件pOnJSockSendComplete;建议使用1可以获得更高的效率
  返回值大于0表示发送成功
  }
  //JSockDisconnect(ThreadID, CliID); 断开当前连接
  InterlockedIncrement(OnJSockReceiveCount);
end;

procedure pOnJSockSendComplete(ThreadID: Integer; CliID: Integer; IIP: Integer; Data: Pchar; Len: Integer) stdcall;
begin
  {当收JSockSend发送数据完毕时触发该事件;
  ThreadID线程序号,主要用户解决多线程共享资源访问问题,这个需要由JSockWork的ThreadID决定
  比如两个线程同时调用JSockWork参数ThreadID分别是1和2,这样这里的ThreadID可能是1或2,1标示第一个线程2标示第二个线程
  CliID是连接的编号,这个号码是0-79999的一个数字,已存在的连接不会有重复
  IIP是客户端的ip地址,可以用函数inet_ntoa转换成字符串ip
  Data是JSockSend发送的数据
  Len是JSockSend发送的数据长度
  }
  //  JSockDisconnect(ThreadID, CliID);
  InterlockedIncrement(OnJSockSendCompleteCount);
end;

procedure pOnJSockDisconnect(ThreadID: Integer; CliID: Integer; IIP: Integer) stdcall;
begin
  {当有客户端断开连接时触发该事件;
  ThreadID线程序号,主要用户解决多线程共享资源访问问题,这个需要由JSockWork的ThreadID决定
  比如两个线程同时调用JSockWork参数ThreadID分别是1和2,这样这里的ThreadID可能是1或2,1标示第一个线程2标示第二个线程
  CliID是连接的编号,这个号码是0-79999的一个数字,已存在的连接不会有重复
  IIP是客户端的ip地址,可以用函数inet_ntoa转换成字符串ip
  }
  InterlockedIncrement(OnJSockDisconnectCount);
end;

procedure pOnJSockError(ThreadID: Integer; CliID: Integer; IIP: Integer; ErrorType: Integer; ErrorCode: Integer) stdcall;
begin
  {当有有错误或警告发生时触发该事件;
  ThreadID线程序号,主要用户解决多线程共享资源访问问题,这个需要由JSockWork的ThreadID决定
  比如两个线程同时调用JSockWork参数ThreadID分别是1和2,这样这里的ThreadID可能是1或2,1标示第一个线程2标示第二个线程
  CliID是连接的编号,这个号码是0-79999的一个数字,已存在的连接不会有重复
  IIP是客户端的ip地址,可以用函数inet_ntoa转换成字符串ip
  ErrorType错误类型,大于0表示警告,小于等于0表示错误,警告对服务器或客户端继续运行是没有影响的,不用处理就行
  ErrorCode错误编号,这里是标准的windows错误编号
  }
  //JSockDisconnect(ThreadID, CliID); 断开当前连接

  if ErrorType > 0 then
  begin
    InterlockedIncrement(OnJSockErrorCount1);
  end
  else
  begin
    InterlockedIncrement(OnJSockErrorCount2);
  end;
end;

var
  strline: string;
  host: string;
  port: integer;
  KeepAlive: integer;
  SameIpCount: integer;
  TickCountOld, TickCountNew: dword;
begin
  writeln('请输入监听的IP地址:');
  readln(strline);
  host := strline;
  writeln('请输入监听的端口:');
  readln(strline);
  port := strtoint(strline);
  writeln('请输入测试连接的数据包多少秒发送一次:'); //0表示使用系统设置
  readln(strline);
  KeepAlive := strtoint(strline);
  writeln('请输入同一IP最多允许多少个连接:'); //用于防攻击
  readln(strline);
  SameIpCount := strtoint(strline);
  writeln('正在启动服务...');
  if JSockStart(0, pchar(host), port, KeepAlive, SameIpCount, @pOnJSockConnect, @pOnJSockReceive, @pOnJSockSendComplete, @pOnJSockDisconnect, @pOnJSockError) > 0 then
  begin
    writeln('服务启动成功,等待客户端连接...');
    TickCountOld := GetTickCount;
    while true do
    begin
      JSockWork(1, 10); //查询事件,ThreadID线程序号,TimeOut没有事件时等待多少毫秒
      TickCountNew := GetTickCount;
      if TickCountNew - TickCountOld > 5000 then
      begin
        writeln('------------------------------------------------------');
        writeln('当前连接数量:' + inttostr(OnJSockConnectCount-OnJSockDisconnectCount));
        writeln('累计连接数量:' + inttostr(OnJSockConnectCount));
        writeln('累计接收次数:' + inttostr(OnJSockReceiveCount));
        writeln('累计发送次数:' + inttostr(OnJSockSendCount));
        writeln('累计完成次数:' + inttostr(OnJSockSendCompleteCount));
        writeln('累计断开次数:' + inttostr(OnJSockDisconnectCount));
        writeln('累计警告次数:' + inttostr(OnJSockErrorCount1));
        writeln('累计错误次数:' + inttostr(OnJSockErrorCount2));
        writeln('------------------------------------------------------');
        TickCountOld := TickCountNew;
      end;
    end;
  end;
end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -