Java和.NET下使用socket

前一段时间做过JAVA的Socket客户端转换为C#的Socket客户端的工作,最近开发的项目又需要用Java代码通过Socket的方式作为客户端去请求服务端交互数据的功能,这次对.NET和Java的一些常用技术点做个记录,由于没有涉及开发大并发量的socket服务器端,对分包、粘包和一些高性能的要求都没有分析过,本篇文章只以它们之间的常用使用方法以及Java的Socket转换为C#代码的方法作一定的记录。

一、Java Socket

在JDK1.4之前,java只能以同步的方式创建socket,异步只能用多线程方式的异步,java.net.ServerSocket 包可以创建服务端的socket处理器,客户端通过java.net.Socket 连接过来如:

private ServerSocket server = null;

private Socket socket = null;

InetAddress address = InetAddress.getByName(“127.0.0.1”);

server = new ServerSocket(3000,10000,address);

//监听窗口,等待连接

socket = server.accept();

这样服务端ServerSocket的accept()方法就会同步阻塞等待客户端连接,在收到客户端socket连接请求后,就会执行后续操作。服务端通过socket.getInputStream()来获取客户端输入的数据流,通过对socket.getOutputStream()读取流进行回写,返回给客户端信息。Socket客户端可以用:

Socket so = new Socket(“127.0.0.1”,3000);

InputStream is = so.getInputStream();

OutputStream os = so.getOutputStream();

的方式建立socket连接,比如这里可以直接对os进行发送数据到服务端:os.write(sendByte)。

JDK1.4后,香港服务器租用,增加了NIO的包可以创建非阻塞的异步Socket服务端和客户端,在java.nio包下java.nio.channels.ServerSocketChannel用于创建socket服务端,java.nio.channels.SocketChannel包用于创建socket接收端或客户端,它们通过java.nio.channels.Selector管理NIO的ServerSocketChannel通道,Selector通过事件的方式响应客户端的请求,为Selector注册事件的方式如:

// 通过open()方法找到Selector

selector = Selector.open();

serverSocketChannel = ServerSocketChannel.open();

// 注册接收请求事件到selector

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

事件还包括:SelectionKey.OP_READ读取事件,SelectionKey.OP_WRITE写操作事件,为serverSocketChannel注册事件后,就可以写一个循环,每当selector.select()接收到值时,就开始判断是什么事件,然后按照事件执行具体逻辑代码。建立异步Socket服务端代码如:

serverSocketChannel = ServerSocketChannel.open();

//配置为非阻塞

serverSocketChannel.configureBlocking(false);

//获取通道关联的服务器套接字

ServerSocket serverSocket = serverSocketChannel.socket();

//服务端绑定IP端口

serverSocket.bind(new InetSocketAddress(“127.0.0.1”, 3000));

这样通过serverSocketChannel建立了服务端监听,然后用上面的Selector为serverSocketChannel添加注册事件即可作为服务端监听各种客户端事件了。

Java中对TCP和UDP分别用不同的包来处理,UDP是用java.net.DatagramSocket包下的方法来处理。

二、.NET Socket

.NET下C#封装的Socket在System.Net.Sockets命名空间下,里面异步、同步的方法均用Socket类即可,并且TCP,虚拟主机,UDP的选择直接根据 Socket的构造函数来确定,比如:Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

ProtocolType可以选择TCP还是UDP,当为UDP时,需要用SocketType.Dgram类型的数据格式。.NET里有封装 TcpListener 和TcpClient来分别处理TCP请求的服务端和客户端,UdpClient 类来处理UDP请求的服务端和客户端,它们是基于Socket套接字的封装。使用上TcpListener、TcpClient和Java的风格很像,通过tcpClient.GetStream()返回数据流再操作数据,而UdpClient是通过直接send,receive的方式发送接收数据。.NET的Socket服务器端建立监听如:

IPEndPoint hostEP = new IPEndPoint(IPAddress.Parse(“127.0.0.1”), port);

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

socket.Bind(hostEP);

socket.Listen(500);

Socket client = socket.Accept();

通过Accept方法同步等待获取一个连接的socket,当然也可以异步的方式等待客户端的连接请求,有新请求后,就可以用这个socket来处理数据。它可以用同步阻塞接收方法,如:

public int Receive(byte[] buffer);

public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags);

等用于同步接收客户端数据,也可以异步接收客户端数据的方式:

可以APM方式:public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state);

或者事件方式:public bool ReceiveAsync(SocketAsyncEventArgs e);

处理数据的方式比如:

byte[] bytesSendStr = new byte[1024];

int bytes = client.Receive(bytesSendStr);

string sendStr = Encoding.UTF8.GetString(bytesSendStr, 0, bytes);

sendStr = “服务端返回:” + sendStr;

bytesSendStr = Encoding.UTF8.GetBytes(sendStr);

client.Send(bytesSendStr, bytesSendStr.Length,SocketFlags.None);

服务端接收数据应该反复Receive客户端数据,直到接收数据返回的整数小于1,防止没有读取完数据,并且读取结果我觉得最好读取到byte里,因为一般socket都可能会用byte的前面字段作为标识,比如标识收取数据的长度,数据类型等。

作为Socket服务端,一般都要能同时处理大量的客户端socket请求,因此单线程来处理肯定不行,当每accept到一个客户端请求后,就开启一个线程来处理,存在大量线程开启的问题,并且客户端请求后发送数据和服务端返回数据等会导致服务端同步等待,造成线程消耗资源的浪费。因此一般服务端都会用异步的方式来处理客户端的请求。

三、Java Socket和C# Socket的不同

一般它们的区别有:创建socket的方式不一样;发送数据和接收数据方式不一样;还有就是Java中一般是用方法的方式设置配置参数,网站空间,.NET是以属性的方式直接设置。

下面以TCP的方式说明几个,如Java创建客户端方式:

Socket socket = new Socket(“127.0.0.1”,3000);

.NET创建客户端方式:

Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//服务器的IP和端口

IPEndPoint ie = new IPEndPoint(IPAddress.Parse(“127.0.0.1”), 3000);

newclient.Connect(ie);

Java发送接收数据方式:

Socket socket = new Socket(“127.0.0.1”,3000);

InputStream is = socket.getInputStream();

OutputStream os = socket.getOutputStream();

//发送数据

os.write(sendByte);

//读取服务端数据

returnStr = InputStreamTOString(is);

.NET发送接收数据方式:

byte[] msg = Encoding.UTF8.GetBytes(content);

//newclient.ReceiveTimeout = 10000;

//直接发送

int bytesSent = newclient.Send(msg);

//直接接收服务端

int bytesRec = newclient.Receive(data);

设置Socket参数的方法,比如Java设置参数:

//让socket及时发送,防止缓存数据不多时不发送

socket.setTcpNoDelay(true);

//接收数据超时时间

socket.setSoTimeout(30000);

.NET对应Java的上述设置为:

newclient.NoDelay = true;

newclient.ReceiveTimeout = 30000;

命运掌握在自己手中

Java和.NET下使用socket

相关文章:

你感兴趣的文章:

标签云: