zoukankan      html  css  js  c++  java
  • 用Delphi编写Socket通信程序

     

    笔者在工作中遇到对局域网中各工作站与服务器之间进行Socket通信的问题。现在将本人总结出来的TServerSocket和TClientSocket两个组件的基本用法写出来,希望与您分享。

      ClientSocket组件为客户端组件。它是通信的请求方,也就是说,它是主动地与服务器端建立连接。

      ServerSocket组件为服务器端组件。它是通信的响应方,也就是说,它的动作是监听以及被动接受客户端的连接请求,并对请求进行回复。

      ServerSocket组件可以同时接受一个或多个ClientSocket组件的连接请求,并与每个ClientSocket组件建立单独的连接,进行单独的通信。因此,一个服务器端可以为多个客户端服务。

      设计思路

      本例包括一个服务器端程序和一个客户端程序。客户端程序可以放到多个计算机上运行,同时与服务器端进行连接通信。

      本例的重点,一是演示客户端与服务器端如何通信;二是当有多个客户端同时连接到服务器端时,服务器端如何识别每个客户端,并对请求给出相应的回复。为了保证一个客户端断开连接时不影响其它客户端与服务器端的通信,同时保证服务器端能够正确回复客户端的请求,在本例中声明了一个记录类型:

      type
      client_record=record
      CHandle: integer; //客户端套接字句柄
      CSocket:TCustomWinSocket; //客户端套接字
      CName:string; //客户端计算机名称
      CAddress:string; //客户端计算机IP地址
      CUsed: boolean; //客户端联机标志
    end;

      利用这个记录类型数据保存客户端的信息,同时保存当前客户端的连接状态。其中,CHandle保存客户端套接字句柄,以便准确定位每个与服务器端保持连接的客户端;Csocket保存客户端套接字,通过它可以对客户端进行回复。Cused记录当前客户端是否与服务器端保持连接。

      下面对组件ServerSocket和ClientSocket的属性设置简单说明。


    本文来自: 编程入门网 http://www.bianceng.cn/Programming/Delphi/jc/200711/5431.htm

    ServerSocket的属性:

      · Port,是通信的端口,必须设置。在本例中设置为1025;

      · ServerTypt,服务器端读写信息类型,设置为stNonBlocking表示异步读写信息,本例中采用这种方式。

      · ThreadCacheSize,客户端的最大连接数,就是服务器端最多允许多少客户端同时连接。本例采用默认值10。

      其它属性采用默认设置即可。

      ClientSocket的属性:

      · Port,是通信的端口,必须与服务器端的设置相同。在本例中设置为1025;

      · ClientType,客户端读写信息类型,应该与服务器端的设置相同,为stNonBlocking表示异步读写信息。

      · Host,客户端要连接的服务器的IP地址。必须设置,当然也可以在代码中动态设置。

      其它属性采用默认设置即可。

      程序源代码:

      · 服务器端源码(uServerMain.pas):

      unit uServerMain;
    interface
      uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       ScktComp, ToolWin, ComCtrls, ExtCtrls, StdCtrls, Buttons;
      const
       CMax=10; //客户端最大连接数
      type
       client_record=record
       CHandle: integer; //客户端套接字句柄
       CSocket:TCustomWinSocket; //客户端套接字
       CName:string; //客户端计算机名称
       CAddress:string; //客户端计算机IP地址
       CUsed: boolean; //客户端联机标志
      end;
      type
       TfrmServerMain = class(TForm)
       ServerSocket: TServerSocket;
       ControlBar1: TControlBar;
       ToolBar1: TToolBar;
       tbConnect: TToolButton;
       tbClose: TToolButton;
       tbDisconnected: TToolButton;
       Edit1: TEdit;
       Memo1: TMemo;
       StatusBar: TStatusBar;
       procedure tbConnectClick(Sender: TObject);
       procedure tbDisconnectedClick(Sender: TObject);
       procedure ServerSocketClientRead(Sender: TObject;Socket: TCustomWinSocket);
       procedure ServerSocketListen(Sender: TObject;Socket: TCustomWinSocket);
       procedure ServerSocketClientConnect(Sender: TObject;Socket: TCustomWinSocket);
       procedure ServerSocketClientDisconnect(Sender: TObject;Socket: TCustomWinSocket);
       procedure tbCloseClick(Sender: TObject);
       procedure FormCreate(Sender: TObject);
       procedure FormClose(Sender: TObject; var Action: TCloseAction);
       procedure ServerSocketGetSocket(Sender: TObject; Socket: Integer;
       var ClientSocket: TServerClientWinSocket);
       procedure ServerSocketClientError(Sender: TObject;
       Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
       var ErrorCode: Integer);
       private
       {
        Private declarations
       }
       public
       {
        Public declarations
       }
       session: array[0..CMax] of client_record; //客户端连接数组
       Sessions: integer; //客户端连接数
      end;
      var
       frmServerMain: TfrmServerMain;
       implementation
       {$R *.DFM}
       //打开套接字连接,并使套接字进入监听状态
       procedure TfrmServerMain.tbConnectClick(Sender: TObject);
      begin
       ServerSocket.Open ;
      end;
      //关闭套接字连接,不再监听客户端的请求
      procedure TfrmServerMain.tbDisconnectedClick(Sender: TObject);
      begin
       ServerSocket.Close;
       StatusBar.Panels[0].Text :='服务器套接字连接已经关闭,无法接受客户端的连接请求.';
      end;
      //从客户端读取信息
      procedure TfrmServerMain.ServerSocketClientRead(Sender: TObject;Socket: TCustomWinSocket);
      var
       i:integer;
      begin
       //将从客户端读取的信息添加到Memo1中
       Memo1.Lines.Add(Socket.ReceiveText);
       for i:=0 to sessions do
       begin
        //取得匹配的客户端
        if session[i].CHandle = Socket.SocketHandle then
        begin
         session[i].CSocket.SendText('回复客户端'+session[i].CAddress+' ==> '+Edit1.Text);
        end;
       end;
      end;
      //服务器端套接字进入监听状态,以便监听客户端的连接
      procedure TfrmServerMain.ServerSocketListen(Sender: TObject;Socket: TCustomWinSocket);
      begin
       StatusBar.Panels[0].Text :='等待客户端连接...';
      end;
      //当客户端连接到服务器端以后
      procedure TfrmServerMain.ServerSocketClientConnect(Sender: TObject;
    Socket: TCustomWinSocket);
      var
       i,j:integer;
      begin
       j:=-1;
       for i:=0 to sessions do
       begin
        //在原有的客户端连接数组中有中断的客户端连接
        if not session[i].CUsed then
        begin
         session[i].CHandle := Socket.SocketHandle ;//客户端套接字句柄
         session[i].CSocket := Socket; //客户端套接字
         session[i].CName := Socket.RemoteHost ; //客户端计算机名称
         session[i].CAddress := Socket.RemoteAddress ;//客户端计算机IP
         session[i].CUsed := True; //连接数组当前位置已经占用
         Break;
        end;
       j:=i;
      end;
      if j=sessions then
      begin
       inc(sessions);
       session[j].CHandle := Socket.SocketHandle ;
       session[j].CSocket := Socket;
       session[j].CName := Socket.RemoteHost ;
       session[j].CAddress := Socket.RemoteAddress ;
       session[j].CUsed := True;
      end;
      StatusBar.Panels[0].Text := '客户端 '+Socket.RemoteHost + ' 已经连接';
    end;
    //当客户端断开连接时
    procedure TfrmServerMain.ServerSocketClientDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
    var
      i:integer;
    begin
      for i:=0 to sessions do
      begin
       if session[i].CHandle =Socket.SocketHandle then
       begin
        session[i].CHandle :=0;
        session[i].CUsed := False;
        Break;
       end;
      end;
      StatusBar.Panels[0].Text :='客户端 '+Socket.RemoteHost + ' 已经断开';
    end;
    //关闭窗口
    procedure TfrmServerMain.tbCloseClick(Sender: TObject);
    begin
      Close;
    end;
    procedure TfrmServerMain.FormCreate(Sender: TObject);
    begin
      sessions := 0;
    end;
    procedure TfrmServerMain.FormClose(Sender: TObject;var Action: TCloseAction);
    begin
      ServerSocket.Close ;
    end;
    //当客户端正在与服务器端连接时
    procedure TfrmServerMain.ServerSocketGetSocket(Sender: TObject;
    Socket: Integer; var ClientSocket: TServerClientWinSocket);
    begin
      StatusBar.Panels[0].Text :='客户端正在连接...';
    end;
    //客户端发生错误
    procedure TfrmServerMain.ServerSocketClientError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
    begin
      StatusBar.Panels[0].Text :='客户端'+Socket.RemoteHost +'发生错误!';
      ErrorCode := 0;
    end;
    end.

    · 客户端源码(uClientMain.pas):

      unit uClientMain;
    interface
    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    ScktComp, ComCtrls, ToolWin, ExtCtrls, StdCtrls, Buttons;
    const
      SocketHost = '172.16.1.6'; //服务器端地址
    type
      TfrmClientMain = class(TForm)
      ControlBar1: TControlBar;
      ToolBar1: TToolBar;
      tbConnected: TToolButton;
      tbSend: TToolButton;
      tbClose: TToolButton;
      tbDisconnected: TToolButton;
      ClientSocket: TClientSocket;
      Edit1: TEdit;
      Memo1: TMemo;
      StatusBar: TStatusBar;
      btnSend: TBitBtn;
      procedure tbConnectedClick(Sender: TObject);
      procedure tbDisconnectedClick(Sender: TObject);
      procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
      procedure tbSendClick(Sender: TObject);
      procedure tbCloseClick(Sender: TObject);
      procedure FormShow(Sender: TObject);
      procedure ClientSocketConnect(Sender: TObject;
      Socket: TCustomWinSocket);
      procedure ClientSocketConnecting(Sender: TObject;
      Socket: TCustomWinSocket);
      procedure ClientSocketDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
      procedure FormClose(Sender: TObject; var Action: TCloseAction);
      procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
      private
      { Private declarations }
      public
      { Public declarations }
      end;
      var
       frmClientMain: TfrmClientMain;
       implementation
       {$R *.DFM}
       //打开套接字连接
       procedure TfrmClientMain.tbConnectedClick(Sender: TObject);
       begin
        ClientSocket.Open ;
       end;
       //关闭套接字连接
       procedure TfrmClientMain.tbDisconnectedClick(Sender: TObject);
       begin
        ClientSocket.Close;
       end;
       //接受服务器端的回复
       procedure TfrmClientMain.ClientSocketRead(Sender: TObject;Socket: TCustomWinSocket);
       begin
        Memo1.Lines.Add(Socket.ReceiveText);
       end;
       //发送信息到服务器端
       procedure TfrmClientMain.tbSendClick(Sender: TObject);
       begin
        ClientSocket.Socket.SendText(Edit1.Text);
       end;
       procedure TfrmClientMain.tbCloseClick(Sender: TObject);
       begin
        Close;
       end;
       //设置要连接的服务器端地址
       procedure TfrmClientMain.FormShow(Sender: TObject);
       begin
        ClientSocket.Host := SocketHost;
       end;
       //已经连接到服务器端
       procedure TfrmClientMain.ClientSocketConnect(Sender: TObject;Socket: TCustomWinSocket);
       begin
        tbSend.Enabled := True;
        tbDisconnected.Enabled :=True;
        btnSend.Enabled := True;
        StatusBar.Panels[0].Text := '已经连接到 '+ Socket.RemoteHost ;
       end;
       //正在连接到服务器端
       procedure TfrmClientMain.ClientSocketConnecting(Sender: TObject;Socket: TCustomWinSocket);
       begin
        StatusBar.Panels[0].Text := '正在连接到服务器... ' ;
       end;
       //当断开与服务器端的连接时发生
       procedure TfrmClientMain.ClientSocketDisconnect(Sender: TObject;
    Socket: TCustomWinSocket);
       begin
        tbSend.Enabled := False;
        btnSend.Enabled := False;
        tbDisconnected.Enabled := False;
        StatusBar.Panels[0].Text := '已经断开与 '+ Socket.RemoteHost +' 的连接';
       end;
       procedure TfrmClientMain.FormClose(Sender: TObject;
    var Action: TCloseAction);
       begin
        ClientSocket.Close ;
       end;
       //当与服务器端的连接发生错误时
       procedure TfrmClientMain.ClientSocketError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);
       begin
        StatusBar.Panels[0].Text := '与服务器端的连接发生错误';
        ErrorCode := 0;
       end;
      end.

     

  • 相关阅读:
    前言
    npm安装全局模块之后项目提示找不到的解决
    mybatisPlus自动填充功能
    springMvc跨域的问题
    mybatisPlus逻辑删除
    java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
    Maven 打包指定名称
    Host is not allowed to connect to this MySQL server
    MySQL 8.0 Public Key Retrieval is not allowed
    SpringBoot1.5 项目启动报错 (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')
  • 原文地址:https://www.cnblogs.com/jiangyuxuan/p/1355676.html
Copyright © 2011-2022 走看看