java nio socket实现多线程多用户通信

本程序在客户端异常退出后有时会在服务器端有死循环,望读者知悉

server端代码:

package com.lifeix.d20131009;


import java.io.IOException;
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.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;




public class JFQ_Server {


private static BlockingQueue<Map<String, SelectionKey>> queues = new ArrayBlockingQueue<Map<String, SelectionKey>>(10);
private static final int BUFFER_SIZE = 1024;

private void initServer() throws IOException{
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.socket().bind(new InetSocketAddress(9999));
ssc.register(selector, SelectionKey.OP_ACCEPT);
new Thread(new ReceiveServerThread(selector, queues, BUFFER_SIZE)).start();

}

/**@description:
* @return:void
* @param args
* @throws IOException 
*/


public static void main(String[] args) throws IOException {
new JFQ_Server().initServer();
}


}




class ReceiveServerThread implements Runnable {
private Selector selector;
private int bufferSize;
private BlockingQueue<Map<String, SelectionKey>> queues;
private boolean flag = false;
public ReceiveServerThread(Selector selector,BlockingQueue<Map<String, SelectionKey>> queues,int BUFFER_SIZE) {
this.selector = selector;
this.queues = queues;
this.bufferSize = BUFFER_SIZE;
}

public void run() {
try {
while(!flag) {
System.out.println("waiting connected.......");
selector.select();
Iterator<SelectionKey> keys =  selector.selectedKeys().iterator();
while(keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if(key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
SelectionKey clientKey = sc.register(selector, SelectionKey.OP_READ); 
((SocketChannel)clientKey.channel()).write(ByteBuffer.wrap("echo:connect server success[]".getBytes()));
System.out.println(sc.socket().getInetAddress().getHostAddress() + " 已连接");
}
if(key.isReadable()) {
read(key);

}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private void read(SelectionKey key) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
SocketChannel sc = (SocketChannel) key.channel();
try {
sc.read(buffer);
buffer.flip();
} catch(IOException e) {
sc.close();
}
String data = new String(buffer.array(),"UTF-8");
System.out.println("data:" + data);
if(null == data || "".equals(data) || data.indexOf("[]") < 0) {
return;
}
data = data.substring(0,data.lastIndexOf("[]"));
if("list".equals(data)) {
sc.write(ByteBuffer.wrap((queues.toString()+"[]").getBytes("UTF-8")));
return;

if(data.startsWith("#name")) {
Map<String, SelectionKey> map = null;
if(queues.isEmpty()) {
map = new HashMap<String, SelectionKey>();
} else {
map = queues.element();
}
map.put(data.substring(data.indexOf(":")+1), key);
queues.clear();
queues.add(map);
return;
}
System.out.println("from client: " + data);
String name = data.substring(0,data.indexOf("#"));
String targetName = data.substring(data.indexOf("|") + 1, data.lastIndexOf("|"));
String msg = data.substring(data.lastIndexOf("|") + 1);
Iterator<Map<String, SelectionKey>> its = queues.iterator();
if("exit".equals(targetName)) {
if(its.hasNext()) {
Map<String, SelectionKey> map = its.next();
map.remove(name);
System.out.println(name + "已经下线....");
queues.clear();
queues.add(map);
key.cancel();
}
}  else {

if(its.hasNext()) {

Map<String, SelectionKey> map = its.next();
SelectionKey targetSocket = map.get(targetName);
if("setname".equals(targetName)) {
map.remove(name);
map.put(msg, key);
queues.clear();
queues.add(map);
return;
}
if(null != targetSocket) {
SocketChannel tsc = (SocketChannel) targetSocket.channel();
tsc.write(ByteBuffer.wrap(( name + " :" + msg + "[]").getBytes("UTF-8")));
} else {
sc.write(ByteBuffer.wrap(("没有【" + targetName + "】[]").getBytes("UTF-8")));
}
}
}
}

}


客户端端实现第一种:

package com.lifeix.d20131009;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;


public class JFQ_Client2 {

private static final int BUFFER_SIZE = 1024;
private static String name = "lifeix";
private static String charset= "UTF-8";
private Selector selector;
private void initClient() throws IOException {
System.out.println("list命令显示当前在线用户\nsetname|新名字  修改你的网名\n   send|对方名字|消息   发送消息\n exit命令退出");
selector = Selector.open();
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_CONNECT);
sc.connect(new InetSocketAddress("localhost", 9999));
new Thread(new WriteClientThread2(BUFFER_SIZE, name, sc, selector)).start();
while(true) {
selector.select();
Set<SelectionKey> sets = selector.selectedKeys();
Iterator<SelectionKey> keys =  sets.iterator();
while(keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
SocketChannel channel = (SocketChannel) key.channel();   
if(key.isConnectable()) {
if(channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.write(ByteBuffer.wrap(("#name:" + name + "[]").getBytes(charset)));
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ); 
}
if(key.isReadable()) {
read(channel);
}
}
}
}

private void read(SocketChannel sc) throws IOException,SocketException {
StringBuffer sb = new StringBuffer();
ByteBuffer buffer = ByteBuffer.allocate(1024);
if(sc.read(buffer) > 0) {
buffer.flip();
sb.append(new String(buffer.array(),charset));
}
String data = sb.toString();
if(null != data && !"".equals(data)) {
data = data.substring(0, data.lastIndexOf("[]"));
}
System.out.println(data);
System.out.println();
}

/**@description:
* @return:void
* @param args
* @throws IOException 
*/


public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
new JFQ_Client2().initClient();
}



}
class WriteClientThread2 implements Runnable {
private Selector selector;
private SocketChannel sc;
private String name;
private static String charset= "UTF-8";
public WriteClientThread2(int bufferSize, String name, SocketChannel sc, Selector selector) {
this.name = name;
this.sc = sc;
this.selector = selector;
}

public void run() {
boolean flag = false;

while(!flag) {
String command = null;
try {
command = getInputCommand();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("command:" + command);

if(null != command && !"".equals(command.trim())) {
if("list".equals(command)) {
try {
sc.write(ByteBuffer.wrap("list[]".getBytes(charset)));
continue;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if(command.startsWith("setname")) {
String temp = name;
this.name = command.substring(command.indexOf("|") + 1);
if(this.name == null || "".equals(this.name)) {
System.out.println("给个名字吧....");
continue;
}
try {
sc.write(ByteBuffer.wrap((temp + "#|setname|" + name + "[]").getBytes(charset)));
continue;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if("exit".equals(command)) {
try {
flag = true;
sc.write(ByteBuffer.wrap((name + "#|exit|''[]").getBytes(charset)));
sc.close();
selector.close();
} catch (IOException e) {
System.out.println(name + "下线");
}
} else {
if(command.indexOf("|") < 0) {
System.out.println("invalidate 【" + command + "】");
continue;
}
String cmd = command.substring(0, command.indexOf("|"));
String content = command.substring(command.indexOf("|")+1);
System.out.println(content);
if("send".equals(cmd) && null != content && !"".equals(content) && !"".equals(name)) {
try {
sc.write(ByteBuffer.wrap((name + "#|" + content + "[]").getBytes(charset)));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

} else {
System.out.println("命令错误");
}
}
} else {
System.out.println("invalidate" + command);
}
}
}

private String getInputCommand() throws IOException {
System.out.print("发送消息:");
InputStream is = System.in;
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
if((line = br.readLine()) != null) {
return line.trim();
}
System.out.println();
return "";
}
}


客户端实现2:

package com.lifeix.d20131009;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;


public class JFQ_Client {

private static final int BUFFER_SIZE = 1024;
private static String name = "lifeix";
private static String charset= "UTF-8";
private void initClient() throws IOException {
Socket socket = new Socket("localhost",9999);
OutputStream os = socket.getOutputStream();
os.write(("#name:" + name + "[]").getBytes(charset));
os.flush();

new Thread(new ReadClientThread(BUFFER_SIZE,socket, name)).start();
new Thread(new WriteClientThread(BUFFER_SIZE,socket, name, os)).start();
}



/**@description:
* @return:void
* @param args
* @throws IOException 
*/


public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
new JFQ_Client().initClient();
}


}


class ReadClientThread implements Runnable {


private int bufferSize;
private Socket socket;
private String name;
private OutputStream os;
private boolean flag = false;
private static String charset= "UTF-8";
public ReadClientThread(int bufferSize, Socket socket, String name) {
this.bufferSize = bufferSize;
this.socket = socket;
this.name = name;
try {
os = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void run() {
try {
System.out.println("exit命令下线");
while(!flag) {
InputStream is = socket.getInputStream();
read(is);
}
} catch (IOException e) {

} catch(Exception we) {
System.out.println(name + "下线");

}
}
private void read(InputStream is) throws IOException,SocketException {
StringBuffer sb = new StringBuffer();
byte[] buffer = new byte[bufferSize];
if(is.read(buffer) > 0) {
sb.append(new String(buffer,charset));
}
String data = sb.toString();
if(null != data && !"".equals(data)) {
data = data.substring(0, data.lastIndexOf("[]"));
}
System.out.println(data);
System.out.println();
}
}


class WriteClientThread implements Runnable {


private Socket socket;
private String name;
private OutputStream os;
private static String charset= "UTF-8";
public WriteClientThread(int bufferSize, Socket socket, String name,OutputStream os) {
this.socket = socket;
this.name = name;
this.os = os;
}

public void run() {
boolean flag = false;
while(!flag) {
String command = null;
try {
command = getInputCommand();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("command:" + command);

if(null != command && !"".equals(command.trim())) {
if("list".equals(command)) {
try {
os.write("list[]".getBytes(charset));
os.flush();
continue;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if(command.startsWith("setname")) {
String temp = name;
this.name = command.substring(command.indexOf("|") + 1);
if(this.name == null || "".equals(this.name)) {
System.out.println("给个名字吧....");
continue;
}
try {
os.write((temp + "#|setname|" + name + "[]").getBytes(charset));
os.flush();
continue;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if("exit".equals(command)) {
try {
flag = true;
os.write((name + "#|exit|''[]").getBytes(charset));
os.flush();
os.close();
} catch (IOException e) {
System.out.println(name + "下线");
}
} else {
if(command.indexOf("|") < 0) {
System.out.println("invalidate 【" + command + "】");
continue;
}
String cmd = command.substring(0, command.indexOf("|"));
String content = command.substring(command.indexOf("|")+1);
if("send".equals(cmd) && null != content && !"".equals(content) && !"".equals(name)) {
try {
os.write((name + "#|" + content + "[]").getBytes(charset));
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

} else {
System.out.println("命令错误");
}
}
} else {
System.out.println("invalidate" + command);
}
}
}

private String getInputCommand() throws IOException {
System.out.print("发送消息:");
InputStream is = System.in;
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
if((line = br.readLine()) != null) {
return line.trim();
}
System.out.println();
return "";
}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值