简体   繁体   English

Delphi与Java之间的套接字通信

[英]Socket Communication between Delphi and Java

I want to create a socket-communication between Delphi6 and Eclipse at localhost. 我想在本地主机的Delphi6和Eclipse之间创建套接字通信。 The Delphi-Code seems to work, i can send data from Delphi-Server to Delphi-Client. Delphi代码似乎有效,我可以将数据从Delphi-Server发送到Delphi-Client。 Now i want to send data from same Delphi-Server to Java-Client. 现在我想将数据从同一个Delphi服务器发送到Java客户端。 Following code i used from several examples. 以下代码是我从几个示例中使用的代码。 The connection between Delphi and Java seems established, but at the while-loop (stdIn.readLine()) the programm doesnt work anymore. Delphi和Java之间的连接似乎已经建立,但是在while循环(stdIn.readLine())上,程序不再起作用。 There is no exception. 也不例外。 The programm just stops to work. 该程序只是停止工作。 How can i read data from Delphi-server? 如何从Delphi服务器读取数据?

Thanks! 谢谢!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class JavaClientSocketEx {
    public static void main(String[] args) {
        try {
            Socket echoSocket = new Socket("127.0.0.1", 10003);
            PrintWriter out =
                new PrintWriter(echoSocket.getOutputStream(), true);
            BufferedReader in =
                new BufferedReader(
                    new InputStreamReader(echoSocket.getInputStream()));
            BufferedReader stdIn =
                new BufferedReader(
                    new InputStreamReader(System.in));
            String userInput;
            echoSocket.close();
            while ((userInput = stdIn.readLine()) != null) { // at this point the programm doesnt work anymore!
                out.println(userInput);
                System.out.println("echo: " + in.readLine());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

edit: Delphi-code 编辑:德尔福代码

unit Unit1;

interface

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

type
  CustomRec = record
    Zahl: byte;
end;
TForm1 = class(TForm)
    Edit1: TEdit;
    Timer1: TTimer;
    sendenButton: TButton;
    Edit2: TEdit;
    ClientSocket1: TClientSocket;
    ServerSocket1: TServerSocket;
    procedure Timer1Timer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure sendenButtonClick(Sender: TObject);
    procedure ServerSocket1ClientError(Sender: TObject;
      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
      var ErrorCode: Integer);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  senden : boolean;

implementation

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
var
text : string;
begin

        text :=  Edit1.Text;
        ClientSocket1.Socket.SendText(text);

end;

procedure TForm1.FormActivate(Sender: TObject);
begin
        sendenButton.Caption := 'Send';
        senden := false;
        ClientSocket1.Port := 10003;
        ClientSocket1.Host := '127.0.0.1';
        ClientSocket1.Active := true;
        ServerSocket1.Port := 10003;
        ServerSocket1.Active := true;

end;

procedure TForm1.sendenButtonClick(Sender: TObject);
begin

  if senden then
   begin
        senden := false;
        sendenButton.Caption := 'Send';
        Timer1.Enabled := false;
   end
  else
   begin
        senden :=true;
        sendenButton.Caption := 'Stopp';
        Timer1.Enabled := true;
  end;
end;

procedure TForm1.ServerSocket1ClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
Errorcode := 0;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var  Rec: CustomRec;
begin
     edit2.Text := Socket.ReceiveText;
     rec.Zahl:=StrToInt(Edit2.Text);
     Socket.SendBuf(Rec,sizeof(Rec));
end;

procedure TForm1.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
Errorcode :=0;
end;

end.

The delphi-client starts to send data form first edit-Element (thats the input) periodicly in one-second-interval after I clicked on "sendenButton". 在单击“ sendenButton”后,delphi客户端开始以一秒钟为间隔定期从第一个edit-Element(即输入)发送数据。 The second edit-Element is the output of the received data. 第二个edit-Element是接收到的数据的输出。 It stops to send, after I clicked this button again. 再次单击此按钮后,它停止发送。

在此处输入图片说明

  1. An issue can be in the while loop where you are trying to read and write on an already closed socket. 问题可能在while循环中,您试图在已经关闭的套接字上进行读写。

     echoSocket.close(); while ((userInput = stdIn.readLine()) != null) { // at this point the programm doesnt work anymore! out.println(userInput); . . . 

    This can be solved moving the echoSocket.close(); 这可以通过移动echoSocket.close();来解决echoSocket.close(); after the loop. 循环后。
    After that the Java client works; 之后,Java客户端开始工作。 now the issue is in the server. 现在问题出在服务器上。

  2. The Delphi client is bound to the server and takes precedence over the Java one. Delphi客户端绑定到服务器,并且优先于Java客户端。
    To solve this, disable the Delphi client: 要解决此问题,请禁用Delphi客户端:

     //ClientSocket1.Active := true; 

    After that the server works. 在那之后服务器工作。

  3. At this point, when you send a number through the console, say 42 , the server raises an exception: 此时,当您通过控制台发送数字(例如42 ,服务器会引发异常:

    Project Project1.exe raised an exception class EConvertError with message ''42 项目Project1.exe引发异常类EConvertError,消息为“ 42”
    ' is not a valid integer value'. ' 不是有效的整数值'。

    The issue happens in the ServerSocket1ClientRead mehod with this instruction: 使用以下指令在ServerSocket1ClientRead发生此问题:

     rec.Zahl := StrToInt(Edit2.Text); 

    Because the string received by the sockect is 因为该原型收到的字符串是

     '42'#$D#$A 

    You may consider to sanitize the text: 您可以考虑对文本进行清理:

     rec.Zahl := StrToInt(StringReplace(Trim(Edit2.Text), '''', '', [rfReplaceAll])); 
  4. When you send the reply to the client, the message terminator #$D#$A is missing. 当您将答复发送给客户端时,消息终止符#$D#$A丢失了。 The line 线

     Socket.SendBuf(Rec, sizeof(Rec)); 

    has to be changed like 必须像

     Socket.SendText(IntToStr(rec.Zahl) + #13#10); 

    This solves the blocking client issue. 这解决了阻止客户端的问题。


The edited programs follow - I have moved the logic from the OnActivate to the OnCreate form event: 编辑后的程序如下-我将逻辑从OnActivate移到了OnCreate表单事件:

The Delphi server/client Delphi服务器/客户端

unit Unit1;

interface

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

type
  CustomRec = record
    Zahl: Byte;
  end;

TForm1 = class(TForm)
  Edit2: TEdit;
    Edit1: TEdit;
    sendenButton: TButton;
  procedure ServerSocket1ClientError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
  procedure ServerSocket1ClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
  procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
    ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  procedure FormCreate(Sender: TObject);
    procedure sendenButtonClick(Sender: TObject);
private
  { Private-Deklarationen }
  ClientSocket1: TClientSocket;
  ServerSocket1: TServerSocket;
public
  { Public-Deklarationen }
end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClientSocket1 := TClientSocket.Create(Self);
  ClientSocket1.OnError := ClientSocket1Error;

  ServerSocket1 := TServerSocket.Create(Self);
  ServerSocket1.OnClientError := ServerSocket1ClientError;
  ServerSocket1.OnClientRead := ServerSocket1ClientRead;

  ClientSocket1.Port := 10003;
  ClientSocket1.Host := '127.0.0.1';
  //ClientSocket1.Open;

  ServerSocket1.Port := 10003;
  ServerSocket1.Open;
end;

procedure TForm1.sendenButtonClick(Sender: TObject);
begin
  sendenButton.Enabled := False;
  ClientSocket1.Open;
  ClientSocket1.Socket.SendText(Edit1.Text);
  ClientSocket1.Close;
  sendenButton.Enabled := True;
end;

procedure TForm1.ServerSocket1ClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  Errorcode := 0;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  rec: CustomRec;
  sInt, reply: string;
  iInt, iCode: Integer;
begin
  edit2.Text := Socket.ReceiveText;

  sInt := StringReplace(Trim(Edit2.Text), '''', '', [rfReplaceAll]);
  Val(sInt, iInt, iCode);

  if iCode = 0 then begin
    if iInt in [Low(Byte)..High(Byte)] then begin
      rec.Zahl := iInt;
      reply := IntToStr(rec.Zahl);
    end;
  end
  else
    reply := '-1';

  Socket.SendText(reply + #13#10);
end;

procedure TForm1.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  Errorcode := 0;
end;

end.

The Java client Java客户端

public static void main(String[] args) throws UnknownHostException, IOException {

    Socket echoSocket = new Socket("127.0.0.1", 10003);
    try {
        PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
        String userInput;

        while ((userInput = stdIn.readLine()) != null) {

            //the next 2 lines resume like: if you have to die, die fast
            int value = Integer.parseInt(userInput);//ensure that input is an Integer
            assert (value >= 0 && value <= 255);// ensure that the Integer is in the Delphi's Byte range

            out.println(value);

            System.out.println("server replies: " + in.readLine());
        }
    } finally {
        echoSocket.close();
    }            
}

Apart from the implementation which uses the writeLine and readLine , a message can be sent to and read from the server using the DataOutput.writeUTF and DataInput.readUTF methods: 除了使用writeLinereadLine的实现之外,还可以使用DataOutput.writeUTFDataInput.readUTF方法将消息发送到服务器或从服务器读取消息:

Socket echoSocket = new Socket("127.0.0.1", 10003);
OutputStream os = echoSocket.getOutputStream();
DataOutputStream out = new DataOutputStream(os);
out.writeUTF("Hi, it's me!");//your message to the server

InputStream in = echoSocket.getInputStream();
DataInputStream din = new DataInputStream(in);
System.out.println("Server response: " + din.readUTF());

echoSocket.close();

Now I found a solution for my problem. 现在,我找到了解决问题的方法。 Thank you very much for your suggestions, fantaghirocco, it helped me to find an answer. 非常感谢您的建议,fantaghirocco,它帮助我找到了答案。 It seems I was not understanding the principles of server-client-architecture. 看来我不了解服务器-客户端体系结构的原理。 I modified your code and now it works fine for me. 我修改了您的代码,现在对我来说很好用。

Delphi-Code: 德尔福代码:

unit Unit1;

interface

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

type
  CustomRec = record
    Zahl: Byte;
  end;

TForm1 = class(TForm)
    edit1: TEdit;
    ClientSocket1: TClientSocket;
    ServerSocket1: TServerSocket;
    Label1: TLabel;
  procedure ServerSocket1ClientError(Sender: TObject;
    Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
    var ErrorCode: Integer);
  procedure MyServerSocket1ClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
  procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
    ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure FormActivate(Sender: TObject);
private
public
  { Public-Deklarationen }
end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.ServerSocket1ClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  Errorcode := 0;
end;

procedure TForm1.MyServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  rec: CustomRec;
  sInt, reply: string;
  iInt, errorPos: Integer;
begin
  edit1.Text := Socket.ReceiveText;

  sInt := StringReplace(Trim(Edit1.Text), '''', '', [rfReplaceAll]);
  Val(sInt, iInt, errorPos);

  if errorPos = 0 then begin
    if iInt in [Low(Byte)..High(Byte)] then begin
      rec.Zahl := iInt;
      iInt := iInt +1;
      reply := IntToStr(rec.Zahl);
    end;
  end
  else
    reply := '-1';
    reply := 'reply ' + reply + ' accepted';
  Socket.SendText(reply + #13#10);
end;

procedure TForm1.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  Errorcode := 0;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
  ClientSocket1 := TClientSocket.Create(Self);
  ClientSocket1.OnError := ClientSocket1Error;

  ServerSocket1 := TServerSocket.Create(Self);
  ServerSocket1.OnClientError := ServerSocket1ClientError;
  ServerSocket1.OnClientRead := MyServerSocket1ClientRead;

  ClientSocket1.Port := 10003;
  ClientSocket1.Host := '127.0.0.1';

  ServerSocket1.Port := 10003;
  ServerSocket1.Open;
end;

end.

Delphi-Form: 德尔福表格:

在此处输入图片说明

Java-Code: Java的代码:

class TCPClient {
    private static int input;
public static void main(String[] args) throws UnknownHostException, IOException {

    Socket echoSocket = new Socket("127.0.0.1", 10003);
    Timer timer = new Timer();
    input = 0;
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            try {
                input = input +1;
                doTime(echoSocket, input);
            } catch (IOException e) {
                e.printStackTrace();
            }  
        }
    }, 1000,1000);   
}

private static void doTime(Socket echoSocket, int input) throws IOException {
    try {
        PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
        //the next 2 lines resume like: if you have to die, die fast
        int value = input;//ensure that input is an Integer
        assert (value >= 0 && value <= 255);// ensure that the Integer is in the Delphi's Byte range
        System.out.println("sending server reply number : " + value);
        out.println(value);
        System.out.println("server replies: " + in.readLine());

    } finally {
        //  echoSocket.close();
    }
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM