java Socket与C#通信中中文乱码问题的解决方案

最近正在做一个项目,其中遇到了一个问题就是java与.NET之间的通信问题。具体的问题是这样的:

        客户端使用java,服务器端使用的是C#。两者之间使用基于TCP的Socket通信方式。可是,做了一个测试小例子,结果从客户端传过来的都是乱码。于是上网查,希望可以找到解决方法,可是,网上有好多的答案,经过了很多的实验,都不能很好的解决。没办法只能靠自己一点一点的排查了。

        经过一番努力,最终找到了原因:C#和java的编码方式不同。虽然找到了原因,但是网上关于这个问题的答案也是百家争鸣,在这里就给出源代码,希望对大家有帮助。

首先是客户端的java代码(这是比较简单的部分)

import java.net.*;
import java.io.*;

public class TCPCline{
	public static void main(String[] args) throws Exception{
		try{
			//这里的IP地址是服务器的IP地址,端口号和服务器统一
			Socket s = new Socket("IP地址",端口);
			OutputStream os = s.getOutputStream();
			DataOutputStream dos = new DataOutputStream(os);
			
			String sendStr = "你好!hello";			
			//注意这里,getBytes()中的"UTF-8"
			byte[] bs = sendStr.getBytes("UTF-8");
			 //这里使用的是write(),不是writeUTF(),至于为什么,可以查看java帮助文档,里面讲解了
			dos.write(bs,0,bs.length);
			//这里没有使用下面两句,是因为,当我们关闭客户端的时候,在服务器端也可以记录是哪一个客户端掉线了  
			//dos.close();
			//s.close();
			}catch(ConnectException connExc){
				connExc.printStackTrace();	
				
			}catch(IOException e){
				e.printStackTrace();
			}
	}
}


C#的服务器端代码,在这里说明一下,我们把服务器端的代码放到了一个类库TCPServer

下面是错误日志类代码(客户端发送的消息,以及掉线通知都放到这里

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;

namespace TCPServer
{
    /// <summary>
    /// 错误日志类
    /// </summary>
    public class LogHelper
    {
        public static readonly object objLock = new object();
       /// <summary>
       /// 将错误写入.log文件下
       /// </summary>
       /// <param name="msg">错误信息</param>
       /// <param name="ex">异常</param>
        public static void Err(string msg, Exception ex)
        {
            string s = "";
            if (ex != null)
            {
                s = "err:" + msg + ":" + ex.Message;
            }
            else
            {
               s = msg ;
            }
            //将错误输出到log文件中
            string filename = AppDomain.CurrentDomain.BaseDirectory + "log/" + Convert.ToString(getUnixTime()) + ".log";
            lock (objLock)
            {
                using (System.IO.StreamWriter sw = new System.IO.StreamWriter(filename, true))
                {
                    sw.WriteLine(s);
                    if (ex != null)
                    {
                        sw.WriteLine(ex.StackTrace);
                    }
                   
                    sw.WriteLine("time:" + DateTime.Now.ToString());
                    sw.WriteLine("----------------------------------");
                }
            }
        }

ServerListen类

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


namespace TCPServer
{
    public class ServerListen
    {
        public static void Run(Object iGetClientData)
        {
            IPEndPoint serverIP = new IPEndPoint(IPAddress.Parse("IP地址"), 端口);//本机预使用的IP和端口
            Socket skServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            skServer.Bind(serverIP);
            skServer.Listen(100);//连接客户端的上限

            while (true)
            {
                Socket skClient;
                try
                {
                    //当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
                    skClient = skServer.Accept();
                    
                }
                catch (Exception ex)
                {
                    LogHelper.Err("接收用户连接失败 ServerListen.Run Socket.Accept", ex);
                    continue;
                }

                ThrClient thrC = new ThrClient(skServer, skClient, (IGetClientData)iGetClientData);
                Thread t = new Thread(thrC.Run);
                t.Start();
            }
        }
    }
}
ThrClient类

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

namespace TCPServer
{
    public class ThrClient
    {
        private static readonly StringBuilder sb = new StringBuilder();
        private Socket skServer;
        private Socket skClient;
        private IPEndPoint clientIP;
        private IGetClientData iGetClientData;

        //每次接收发送的临时信息
        private byte[] sendData;//发送的信息
        private byte[] receiveData = new byte[1024];//接收信息
        private int receiveN;
        private int netID;
        /// <summary>
        /// ThrClient构造方法
        /// </summary>
        /// <param name="pSkServer">服务端</param>
        /// <param name="pSkClient">客户端</param>
        public ThrClient(Socket pSkServer, Socket pSkClient,IGetClientData iGetClientData)
        {
            this.skServer = pSkServer;
            this.skClient = pSkClient;
            this.iGetClientData = iGetClientData;

            this.clientIP = (IPEndPoint)this.skClient.RemoteEndPoint;
            //下面一定要使用UTF8而不能使用Uncode
            this.sendData = Encoding.UTF8.GetBytes("success");
            try
            {
                this.skClient.Send(sendData, sendData.Length, SocketFlags.None);//发送信息
            }
            catch (Exception ex)
            {
                LogHelper.Err("发送第一次连接成功信息 ThrClient.ThrClient Socket.Send", ex);
            }
        }

        public void Run()
        {
            while (true)
            {
                try
                {
                    this.receiveN = skClient.Receive(this.receiveData);//接收
                    if (this.receiveN != 0)
                    {
                        string removeMsg = Encoding.UTF8 .GetString(receiveData, 0, receiveN);
                        iGetClientData.getThread(removeMsg);
                     }
                }
                catch (Exception ex)
                {
                    iGetClientData.getClientIP(((IPEndPoint)skClient.RemoteEndPoint).Address);                   
                    break;
                }                
            }
        }
    }
上面是主要的代码,还有一个向外界提供的接口,这里就不贴出来了。


两种语言之间的通信问题真的是挺令人头疼的,我们这也是通过猜测然后多次实验才找到了答案。所以,就像《大话设计模式》中提到的,不痴迷,不成功。









  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值