簡體   English   中英

C#-Server和Java-Client:TCP套接字通信問題

[英]C#-Server and Java-Client: TCP Socket Communication Issues

我使用TCPListner在C#中編寫了一個服務器程序,使用socket在Java中TCPListner了一個客戶端程序,但是我無法將復雜的對象從Java客戶端發送到C#服務器。

當我通過將字符串轉換為字節數組從Java客戶端向C#服務器發送一個簡單的字符串時,它總是在C#server中轉換回String(使用Encoding.utf8.getstring(bytesArray) )時在消息的開頭顯示一些無效字符。 當我從C#傳遞一個字符串到Java客戶端時,它顯示無效的標頭錯誤。

如果任何人有任何替代或知道任何可以解決我的問題的免費API,請幫助我。 我已經嘗試過Java-cs-bridge來發送復雜的對象,但它總是在C#服務器上顯示Exception。

這是代碼:

C#服務器代碼 - 主要功能

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace netSocketServer
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpListener server = new TcpListener(IPAddress.Any, 8888);

            var IP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(ip =>ip.AddressFamily == AddressFamily.InterNetwork).Select(ip =>ip).FirstOrDefault();

            server.Start();
            Console.WriteLine("Server is Running at " + IP.ToString());


            TcpClient clientSocket = server.AcceptTcpClient();
            Console.WriteLine("Client Connected ... ");

            Writer wr = new Writer(clientSocket);
           wr.start(); 

            Reader r = new Reader(clientSocket);
            r.start();

            Console.Read();
        }
    }
}

C#Server Reader類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.IO;


namespace netSocketServer
{
    class Reader
    {
        TcpClient socket;
        NetworkStream ns;

        public Reader(TcpClient s)
        {
            socket = s;
            ns = socket.GetStream() ;
        }
        public void start() 
        {
            new Thread(
                t => {
                    while (true)
                    {
                        try
                        {
                            int size = ns.ReadByte();
                            byte[] buff = new byte[size];

                            ns.Read(buff,0,size);

                            String message = Encoding.UTF8.getString(buff);

                            Console.WriteLine("Message from Client : {0}",message);

                            ns.Flush();
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Client Disconnected : " + e.Message);
                        }
                    }
                }).Start();
        } 

    }
}

C#服務器編寫器類

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace netSocketServer
{
    class Writer
    {
        TcpClient socket;
        NetworkStream ns;

        public Writer(TcpClient s)
        {
            socket = s;
            ns = socket.GetStream();
        }
        public void start() 
        {
            new Thread(
                t => {
                    while (true)
                    {
                        try
                        {
                            Console.Write("Please Enter your Message : ");
                            string Message = Console.ReadLine();
                            byte[] buff = Encoding.UTF8.GetBytes(Message);
                            byte size = (byte)Message.Length;
                            ns.WriteByte(size);
                            ns.Write(buff, 0, buff.Length);
                            ns.Flush();
                        }
                        catch(IOException e)
                        {
                            Console.WriteLine("Client Disconnected : " + e.Message);
                            socket.Close();
                            Thread.CurrentThread.Abort();
                            Console.WriteLine("Press any key to Closse Server .... ");
                        }
                    }
                }).Start();
        } 

    }
}

Java客戶端 - 主要功能

package javaclient.net;

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
/**
 *
 * @author Numan
 */
public class JavaClientNet {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        Socket socket;
        Read r;
        Writer wr;

        Scanner s = new Scanner(System.in);

        try 
        {
            // TODO code application logic here

            System.out.print("Please Enter Server IP : ");
            socket = new Socket(s.next(), 8888);

            wr = new Writer(socket);
            wr.start();

            r = new Read(socket);
            r.start();
        }
        catch (IOException ex) 
        {
            System.out.println(ex.getMessage());   
        }
    }
}

Java客戶端 - 讀者類

package javaclient.net;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

/**
 *
 * @author Numan
 */
public class Read extends Thread
{
    Socket socket;
    ObjectInputStream inStream;

    Read(Socket s)
    {
        socket = s;
        try {
            inStream = new ObjectInputStream(socket.getInputStream());
            }
        catch (IOException ex) 
        {
            System.out.println(ex.getMessage());
        }
    }
    @Override
    public void run()
    {
     while(true)
     {
         try
         {
            String str;
            byte size = inStream.readByte();
            byte[] buf = new byte[size];
            inStream.read(buf);
            str = new String(buf);
            System.out.println("Message form Server : "+str);
         }
         catch(IOException e)
         {
             System.out.println(e.getMessage());
             Thread.currentThread().stop();
         } 
     }   
    }
}

Java客戶端 - Writer類

package javaclient.net;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import javacsconverter.core.tobyte.ToByteConvertHelper;

/**
 *
 * @author Numan
 */
public class Writer extends Thread
{
    Socket socket;
    ObjectOutputStream outStream;
    Scanner scanner = new Scanner(System.in);


    Writer(Socket s)
    {
        socket =s;
        try 
        {
            outStream = new ObjectOutputStream(socket.getOutputStream());
        }
        catch (IOException ex) 
        {
            System.out.println(ex.getMessage());
        }
    }
    @Override
    public void run()
    {
        while(true)
        {
            try 
            {

                System.out.print("Please Enter Your Message : ");


                String str = scanner.nextLine();

                byte[] buff = str.getBytes();

                outStream.write(buff);

                outStream.flush();
            } 
            catch (IOException ex) 
            {
                System.out.println(ex.getMessage());
            }

        }
    }
}

一般注意事項

請不要中止線程(C#和Java)。

C#服務器

課程班

存在數據爭用,因為多個線程使用靜態Console類:

  1. 主線程: Program.Main()方法調用Console.Read()方法;
  2. 工作線程: Writer.start()方法調用Console.ReadLine()方法。

請考慮使用不同的東西替換Program.Main()方法的Console.Read()方法調用,例如Thread.Sleep(Timeout.Infinite)

讀者課

有一個錯誤 - Stream.Read()方法不能保證一次讀取指定“大小”的數組(一次調用),返回值應該用於確定讀取的實際字節數。 讓我們看看最初的實現:

int size = ns.ReadByte();
byte[] buff = new byte[size];

// The Stream.Read() method does not guarantee to read the **whole array** "at once".
// Please use the return value of the method.
ns.Read(buff, 0, size);

String message = Encoding.UTF8.GetString(buff);

更正版本:

/// <summary>
/// Helper method to read the specified byte array (number of bytes to read is the size of the array).
/// </summary>
/// <param name="inputStream">Input stream.</param>
/// <param name="buffer">The output buffer.</param>
private static void ReadFully(Stream inputStream, byte[] buffer)
{
    if (inputStream == null)
    {
        throw new ArgumentNullException("inputStream");
    }

    if (buffer == null)
    {
        throw new ArgumentNullException("buffer");
    }

    int totalBytesRead = 0;
    int bytesLeft = buffer.Length;
    if (bytesLeft <= 0)
    {
        throw new ArgumentException("There is nothing to read for the specified buffer", "buffer");
    }

    while (totalBytesRead < buffer.Length)
    {
        var bytesRead = inputStream.Read(buffer, totalBytesRead, bytesLeft);
        if (bytesRead > 0)
        {
            totalBytesRead += bytesRead;
            bytesLeft -= bytesRead;
        }
        else
        {
            throw new InvalidOperationException("Input stream reaches the end before reading all the bytes");
        }
    }
}

public void start()
{
    ...
    int size = ns.ReadByte();
    byte[] buff = new byte[size];
    ReadFully(ns, buff);
    using (var memoryStream = new MemoryStream(buff, false))
    {
        // The StreamReader class is used to extract the UTF-8 string which is encoded with the byte order mark (BOM).
        using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8))
        {
            string message = streamReader.ReadToEnd();
            Console.WriteLine("Message from Client: {0}", message);
        }
    }
    ...
}

作家班

首先,要描述和確定字節,文本流的順序考慮包括每個消息的字節順序標記(BOM) (例如)。

此外,還有一個錯誤 - 發送錯誤的“緩沖區長度”值。 讓我們看看最初的實現:

string Message = Console.ReadLine();
byte[] buff = Encoding.UTF8.GetBytes(Message);

// Problem: instead of the length of the string, the size of byte array must be used
// because the UTF-8 encoding is used: generally, string length != "encoded number of bytes".
byte size = (byte)Message.Length;
ns.WriteByte(size);
ns.Write(buff, 0, buff.Length);
ns.Flush();

更正版本:

// UTF-8 with BOM.
var encoding = new UTF8Encoding(true);

// Buffer encoded as UTF-8 with BOM.
byte[] buff = encoding.GetPreamble()
    .Concat(encoding.GetBytes(message))
    .ToArray();

// Size of the encoded buffer.
byte size = Convert.ToByte(buff.Length);
ns.WriteByte(size);
ns.Write(buff, 0, buff.Length);
ns.Flush();

備用更正版本 - StreamWriter類用於將字符串編碼為帶字節順序標記(BOM)的UTF-8:

string message = Console.ReadLine();

using (var memoryStream = new MemoryStream())
{
    using (var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8, 1024, true))
    {
        streamWriter.Write(message);
    }
    memoryStream.Flush();

    byte size = Convert.ToByte(memoryStream.Length);
    ns.WriteByte(size);

    memoryStream.Seek(0, SeekOrigin.Begin);
    memoryStream.CopyTo(ns);
    ns.Flush();
}

Java客戶端

讀課

首先,請考慮使用DataInputStream類,因為根據以下問題,以下語句不正確:

ObjectInputStream對先前使用ObjectOutputStream編寫的基元數據和對象進行反序列化。

- java.io.ObjectInputStream類,Java™Platform Standard Ed。 7

流的實例化幾乎相同:

inStream = new DataInputStream(socket.getInputStream());

第二,有一個錯誤 - 讀取字節數組,但忽略返回值(讀取的實際字節數):

String str;
byte size = inStream.readByte();
byte[] buf = new byte[size];

// The InputStream.read() method does not guarantee to read the **whole array** "at once".
// Please use the return value of the method.
inStream.read(buf);
str = new String(buf);

第三,如上所述,包括字節順序標記(BOM)。

更正版本:

// Note: inStream must be an instance of DataInputStream class.
byte size = inStream.readByte();

byte[] buf = new byte[size];
// The DataInputStream.readFully() method reads the number of bytes required to fill the buffer entirely.
inStream.readFully(buf);

// Create in-memory stream for the byte array and read the UTF-8 string.
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
    // The BOMInputStream class belongs to Apache Commons IO library.
    BOMInputStream bomInputStream = new BOMInputStream(inputStream, false)) {
    String charsetName = bomInputStream.getBOMCharsetName();

    // The IOUtils class belongs to Apache Commons IO library.
    String message = IOUtils.toString(bomInputStream, charsetName);
    System.out.println("Message form Server : " + message);
}

作家班

有一個錯誤 - 沒有明確指定編碼。 讓我們看看最初的實現:

String str = scanner.nextLine();
byte[] buff = str.getBytes();

更正版本:

String str = scanner.nextLine();
byte[] byteOrderMarkBytes = ByteOrderMark.UTF_8.getBytes();
byte[] stringBytes = str.getBytes(StandardCharsets.UTF_8);
// The ArrayUtils.addAll() method belongs to Apache Commons Lang library.
byte[] buff = ArrayUtils.addAll(byteOrderMarkBytes, stringBytes);
outStream.writeByte(buff.length);
outStream.write(buff);
outStream.flush();

備用更正版本 - ByteArrayOutputStream類用於連接數組:

String str = scanner.nextLine();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] byteOrderMarkBytes = ByteOrderMark.UTF_8.getBytes();
byteArrayOutputStream.write(byteOrderMarkBytes);
byte[] stringBytes = str.getBytes(StandardCharsets.UTF_8);
byteArrayOutputStream.write(stringBytes);
byteArrayOutputStream.flush();

byte[] buff = byteArrayOutputStream.toByteArray();
outStream.writeByte(buff.length);
outStream.write(buff);
outStream.flush();

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM