Delphi最簡化非同步選擇TCP伺服器

来源:http://www.cnblogs.com/kmhr/archive/2016/09/08/5851637.html
-Advertisement-
Play Games

網上Delphi的Socket伺服器優良代碼,實在少見,索性寫個簡化的非同步Socket伺服器,雖然代碼較少,但卻該有的都有了,使用的是非同步選擇WSAAsyncSelect,減少了編寫線程的繁瑣。可能會問,性能如何?當然使用窗體消息通知,占用的是主線程,偵聽、發送、多個客戶端的接收都一個線程,大量數據 ...


    網上Delphi的Socket伺服器優良代碼,實在少見,索性寫個簡化的非同步Socket伺服器,雖然代碼較少,但卻該有的都有了,使用的是非同步選擇WSAAsyncSelect,減少了編寫線程的繁瑣。可能會問,性能如何?當然使用窗體消息通知,占用的是主線程,偵聽、發送、多個客戶端的接收都一個線程,大量數據時,性能當然是差強人意的,編寫這個代碼目的也不在於此。但是在實際的項目中,大數據量的情況也不多,以下是代碼:(Delphi7編譯)

  1 {
  2    最簡化的消息非同步Socket 非同步選擇WSAAsyncSelect, 沒有64的限制
  3 }
  4 
  5 program SocketDemo;
  6 
  7 {$APPTYPE CONSOLE}
  8 
  9 uses Windows, WinSock;
 10 
 11 const
 12   ListenPort : Word  = 12345;
 13   BufferSize : DWORD = 1024;
 14 
 15 type
 16   TConn = ^TConnData;
 17   TConnData = record
 18     FSocket: TSocket;
 19     FAddrIn: TSockAddr;
 20     Buffer : PChar;
 21     BufLen : Integer;
 22   end;
 23 
 24 procedure DoSocketData(Conn: TConn);
 25 var S: string;
 26 begin
 27   Writeln(Conn.Buffer);
 28   //這裡插入業務處理代碼
 29   S:= 'Server echo';
 30   send(Conn.FSocket, PChar(S)^, Length(S), 0);
 31 end;
 32 
 33 
 34 
 35 //--------- 以下不要修改 -----------
 36 const
 37   wcName : PChar = 'THrWndClass';
 38   WM_SOCKET = {WM_USER}$0400 + 101;        // 自定義消息
 39 
 40 var
 41   AddrInLen: Integer = SizeOf(TSockAddr);
 42 
 43 var FConns: array of TConn;
 44 
 45 function GetFreeConn: Integer;
 46 var i: Integer;
 47 begin
 48   Result:= -1;
 49   for i:=0 to High(FConns) do
 50   if FConns[i]=nil then begin
 51     Result:= i; Break;
 52   end;
 53   if Result<0 then begin
 54     Result:= Length(FConns); SetLength(FConns, Result+1);
 55   end;
 56   FConns[Result]:= New(TConn);
 57   GetMem(FConns[Result].Buffer, BufferSize+1);
 58   FConns[Result].BufLen:= BufferSize;
 59 end;
 60 
 61 function GetCltConn(S: TSocket): Integer;
 62 var i: Integer;
 63 begin
 64   for i:=0 to High(FConns) do
 65   if Assigned(FConns[i]) and (FConns[i].FSocket=S) then begin
 66     Result:= i;  Break;
 67   end;
 68 end;
 69 
 70 procedure FreeConn(S: TSocket);
 71 var id: Integer;
 72 var Conn: TConn;
 73 begin
 74   id:= GetCltConn(S);
 75   Conn:= FConns[id];
 76   if not Assigned(Conn) then Exit;
 77   FreeMem(Conn.Buffer);
 78   CloseSocket(Conn.FSocket);
 79   Dispose(Conn);
 80   FConns[id]:= nil;
 81 end;
 82 
 83 function WndProc(wnd, msg, sock, wm: DWORD): Integer; stdcall;
 84 var id, AddrLen: Integer;
 85 begin
 86   Result:= DefWindowProc(wnd, msg, sock, wm);
 87   if (msg<>WM_SOCKET) or (wm=0) then Exit;
 88   case LoWord(wm) of
 89     FD_ACCEPT:
 90       begin
 91         id:= GetFreeConn;
 92         with FConns[id]^ do begin
 93           FSocket:= Accept(sock, @FAddrIn, @AddrInLen);
 94           WSAAsyncSelect(FSocket, wnd, WM_SOCKET, FD_READ or FD_CLOSE);
 95         end;
 96       end;
 97     FD_READ:
 98       begin
 99         id:= GetCltConn(sock);
100         with FConns[id]^ do begin
101           BufLen:= Recv(sock, Buffer^, BufferSize, 0);
102           if (BufLen<0) or (BufLen>Buflen) then FreeConn(sock) else
103           begin
104             Buffer[BufLen]:= #0;
105             try DoSocketData(FConns[id]) except end;
106           end;
107         end;
108       end;
109     FD_CLOSE: FreeConn(sock);
110   end;
111 end;
112 
113 function MakeWndHandle(WndProc: Pointer; wcName: PChar): HWND;
114 var wc: TWndClass;
115 begin
116   FillChar(wc, SizeOf(wc), 0);
117   wc.lpfnWndProc  := WndProc;
118   wc.hInstance    := HInstance;
119   wc.lpszClassName:= wcName;
120   Windows.RegisterClass(wc);
121   Result:= CreateWindow(wcName,'HrWnd',0,0,0,0,0,0,0,HInstance,nil);
122 end;
123 
124 function SrvListen(Port: Word): Boolean;
125 var Wnd: HWND; S: TSocket; Addr: TSockAddrIn; WSAData: TWSAData;
126 begin
127   WSAStartup($0202, WSAData);
128   Addr.sin_family      := AF_INET;
129   Addr.sin_port        := Swap(Port);
130   Addr.sin_addr.S_addr := 0;
131   S:= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
132   Bind(S, Addr, AddrInLen);
133 
134   Wnd:= MakeWndHandle(@WndProc, wcName);
135   WSAAsyncSelect(S, Wnd, WM_SOCKET, FD_ACCEPT or FD_CLOSE);
136   //Writeln(SysErrorMessage(WSAGetLastError()), ' Wnd: ', Wnd);
137   Listen(S, 5);
138 end;
139 
140 procedure SysFina;
141 begin
142   Windows.UnregisterClass(wcName, HInstance);
143   WSACleanup;
144 end;
145 
146 procedure Stay;
147 var msg: TMsg;
148 begin
149   while GetMessage(msg, 0, 0, 0) do begin
150     TranslateMessage(msg);
151     DispatchMessage (msg);
152   end;
153   PostQuitMessage(0);
154 end;
155 
156 begin
157   //if InitProc <> nil then TProcedure(InitProc);
158   SrvListen(ListenPort);
159   Stay;
160   SysFina;
161   Halt(0);
162 end.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Verilog HDL的語言的運算符的範圍很廣,按照其功能大概可以分為以下幾類: (1)算術運算符 +,-,*,/,% !~ * / % + - << >> < <= > >= == !== ! & ^ ^~ | && || ?: 最高優先順序別 ↓ ↓ ↓ ↓ 最低優先順序別 (2)賦值運算符 =,< ...
  • php添加數據到xml文件中 導讀:php添加數據到xml文件中 xml文件:stu.xml: 複製代碼代碼如下: <?xml version="1.0" encoding="utf-8" ?><AllData><xueshengmen><xuesheng> <name>張三</name> <yuw ...
  • 此bug項目中使用elasticSearch中出現的,原因是,nio事件選擇器,在特性內核下以及jdk6版本中,出現不hold線程,死迴圈獲取事件的bug,導致cup使用率過高; 此bug在官網已被修複:http://bugs.java.com/bugdatabase/view_bug.do?bug ...
  • 一、H5分類 網頁開發,移動開發,移動混合開發, 二、所用知識點: APICloud:APICloud是為了開發APP的,所以如果用H5開發的移動端,需要發送簡訊,獲取照相機等就要用APICloud的了。 aui框架:aui框架就是專門開發移動端的框架。 三、怎樣用H5開發移動端? 我建議如果用H5 ...
  • .NET Getting Started with ASP.NET Core and VS Code Coding Standard Best Practices In C# Wire – Writing one of the fastest .NET serializers Other How D... ...
  • Windows下Nginx配置SSL實現Https訪問(包含證書生成) 首先要說明為什麼要實現https? HTTP全名超文本傳輸協議,客戶端據此獲取伺服器上的超文本內容。超文本內容則以HTML為主,客戶端拿到HTML內容後可根據規範進行解析呈現。因此,HTTP主要負責的是“內容的請求和獲取”。問題 ...
  • 待會蘋果要開發佈會 我寫完這篇文章就準備去看發佈會了,因為我買了好幾包瓜子和啤酒。由於蘋果的保密做的越來越差勁,該曝光的信息差不多全部曝光了,我們這種熬夜看發佈會的只不過是讓這些信息更加真實,或者說是一種習慣了吧,因為每次蘋果和錘子的發佈會都必不可少的守著電腦看。 你要問我最期待什麼新產品?可能是新 ...
  • Django簡介:Django是一個開放源代碼的Web應用框架,由Python寫成。採用了MVC的框架模式,即模型M,視圖V和控制器C。不過在Django實際使用中,Django更關註的是模型(Model)、模板(Template)和視圖(Views),稱為 MTV模式。Django的主要目的是簡便 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...