繁体   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