java,Socket,NIO随笔记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java,Socket,NIO随笔记录相关的知识,希望对你有一定的参考价值。

技术分享

      这个答案答的很好。Socket与SocketChannel是俩套api而已,对于网络tcp通信而言不会关心你上层是用何api实现通信的。所以答案是肯定的。SocketChannel可以设置为非阻塞的,所以在某种情况下性能更好,线程不会被挂住。SocketChannel还能注册selector和感兴趣的事件。selector多路复用器这里就不多做介绍了。

     在这里介绍一下通信过程中数据的流动过程。首先当数据被网卡接收后,会被保存到内核中,电脑进行拆包解析,看源端口号,会将此数据包保存到对应链接的tcp接收缓冲区(有的地方成为Socket缓冲区)。当此缓冲区满了后,会发生的动作是:通知对端TCP协议中的窗口关闭。这便是滑动窗口的实现。保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。这就是TCP的流量控制。(刺猬本人自己理解如有不准确还望提出)

  虾面说一下聊天程序server端的简单实现逻辑。我们要实现私聊,当两个客户端与服务端建立连接后,服务端会保存所有建立连接的客户端信息:包括此客户端的name,Socket或SocketChannel(当建立连接后会返回)。其中A客户端向B客户端发送信息“B,hello!”。服务端收到消息后截取字符串“B”,get出与之对应的Socket(NIO的话为SocketChannel),往其中写入读到的内容。完成私聊。虾面贴出服务端的程序:(格式没了凑活看吧,过几天准备再用netty实现此功能)

package com.server;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import com.server.vo.UserInfo;

public class Nioserver implements Runnable {

private static HashMap<String,UserInfo> users=new HashMap<String,UserInfo>();

private Socket client;

private Selector selector;

private ServerSocketChannel serverChannel;

private volatile boolean stop;

private UserInfo userinfo;

/**
* 初始化多路复用器,绑定监听端口
*/
public NioServer(int port) {
try {
selector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(port), 1024);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}

public void stop() {
this.stop = true;
}

@Override
public void run() {
while (!stop) {
try {
selector.select(1000);
Set<SelectionKey> selectionKeys= selector.selectedKeys();
SelectionKey key=null;
Iterator<SelectionKey> it= selectionKeys.iterator();
while(it.hasNext()){
key=it.next();
it.remove();
try{
handleInput(key);
}catch(Exception e){
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
if(selector!=null){
try{
selector.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

public void handleInput(SelectionKey key) throws IOException{
if(key.isValid()){
if(key.isAcceptable()){
ServerSocketChannel ssc=(ServerSocketChannel) key.channel();
SocketChannel sc= ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
userinfo = new UserInfo();
userinfo.setUsername(sc.getRemoteAddress()+"");
userinfo.setSocket(sc.socket());//这里保存user信息是关键,尤其是保存其socket信息与name对应
users.put(sc.getRemoteAddress()+"", userinfo);
System.out.println(users);
}
if(key.isReadable()){
SocketChannel sc= (SocketChannel) key.channel();
ByteBuffer readBuffer=ByteBuffer.allocate(1024);
int readBytes=sc.read(readBuffer);
if(readBytes>0){
readBuffer.flip();
byte[] bytes=new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String body=new String(bytes,"UTF-8");
String name=body.substring(0,body.lastIndexOf(".")+8);
System.out.println(body);
SocketChannel soc= users.get(name).getSocket().getChannel();

doWrite(soc,body);


}
}
}
}

private void doWrite(SocketChannel channel,String response) throws IOException{
if(response!=null&&response.trim().length()>0){
byte[] bytes=response.getBytes();
ByteBuffer bf=ByteBuffer.allocate(bytes.length);
bf.put(bytes);
bf.flip();
channel.write(bf);
}
}

public static void main(String[] args){
NioServer ns=new NioServer(8088);
ns.run();
}

}

以上是关于java,Socket,NIO随笔记录的主要内容,如果未能解决你的问题,请参考以下文章

170407java基于nio工作方式的socket通信

Java TCP/IP Socket基于NIO的TCP通信(含代码)

Java NIO4:Socket通道

Java NIO4:Socket通道

Java--NIO-TCP Socket

.NET下使用socket.io随笔记录