nio
package helloweenpad;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.Properties;
public class MyFirstNIOServer
{
public static final int PORT=12315;
protected Selector selector;
protected Charset charset=Charset.forName("UTF-8");
protected CharsetEncoder charsetEncoder=charset.newEncoder();
protected CharsetDecoder charsetDecoder=charset.newDecoder();
protected Properties talks=new Properties();
int clientCount;
public MyFirstNIOServer() throws Exception
{
talks.load(new FileInputStream("F:\\talk.properties"));
selector=Selector.open();
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(PORT)); // port
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
// register,为了获取SelectionKey的键
p("Server localhost:"+PORT+" started. waiting for clients. ");
while (true)
{
// selector 线程。select() 会阻塞,直到有客户端连接,或者有消息读入
selector.select();
Iterator<SelectionKey> iterator=selector.selectedKeys().iterator();
while (iterator.hasNext())
{
SelectionKey selectionKey=iterator.next();
iterator.remove(); // 删除此消息
// 并在当前线程内处理。(为了高效,一般会在另一个线程中处理此消息,例如使用线程池等)
handleSelectionKey(selectionKey);
}
}
}
public void handleSelectionKey(SelectionKey selectionKey)
throws Exception
{
if (selectionKey.isAcceptable())
{
// 有客户端进来
clientCount++;
ServerSocketChannel serverSocketChannel=(ServerSocketChannel)selectionKey.channel();
SocketChannel socketChannel=serverSocketChannel.accept();
socketChannel.configureBlocking(false);
Socket socket=socketChannel.socket();
// 立即注册一个 OP_READ 的SelectionKey, 接收客户端的消息
SelectionKey key=socketChannel.register(selector,SelectionKey.OP_READ);
key.attach("第 "+clientCount+" 个客户端 ["
+socket.getRemoteSocketAddress()+"]: ");
p(key.attachment()
+"\t[connected] =========================================");
} else
if (selectionKey.isReadable())
{
// 有消息进来
ByteBuffer byteBuffer=ByteBuffer.allocate(100);
SocketChannel socketChannel=(SocketChannel)selectionKey.channel();
try
{
int len=socketChannel.read(byteBuffer);
// 如果len>0,表示有输入。如果len==0, 表示输入结束。需要关闭
// socketChannel
if (len>0)
{
byteBuffer.flip();
String msg=charsetDecoder.decode(byteBuffer).toString();
// 根据客户端的消息,查找到对应的输出
String newMsg=talks.getProperty(msg)
+"come from Server########\n";
if (newMsg==null)
newMsg="Sorry? I don't understand your message. ";
// UTF-8 格式输出到客户端,并输出一个'n'
socketChannel.write(charsetEncoder.encode(CharBuffer.wrap(newMsg
+"\n")));
p(selectionKey.attachment()
+"\t[recieved]: "
+msg
+" ----->\t[send]: "
+newMsg);
} else
{
// 输入结束,关闭 socketChannel
p(selectionKey.attachment()
+"read finished. close socketChannel. ");
socketChannel.close();
}
} catch (Exception e)
{
// 如果read抛出异常,表示连接异常中断,需要关闭
// socketChannel
e.printStackTrace();
p(selectionKey.attachment()
+"socket closed? ");
socketChannel.close();
}
} else
if (selectionKey.isWritable())
{
p(selectionKey.attachment()
+"TODO: isWritable() ???????????????????????????? ");
} else
if (selectionKey.isConnectable())
{
p(selectionKey.attachment()
+"TODO: isConnectable() ????????????????????????? ");
} else
{
p(selectionKey.attachment()
+"TODO: else. ");
}
}
public static void p(Object object)
{
System.out.println("SSSSSSSSSSS"+object);
}
public static void main(String[] args) throws Exception
{
new MyFirstNIOServer();
}
}
package helloweenpad;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Properties;
import java.util.Random;
public class MyFirstNIOClientTest extends Thread
{
public static void main(String[] args) throws Exception
{
// 开三个客户端线程
for (int i=0; i<3; i++)
{
try
{
new MyFirstNIOClientTest().start();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
public static final String HOST="localhost";
public static final int PORT=12315;
boolean exist=false;
Properties talks=new Properties();
Random random=new Random();
String[] keys;
int messageCount=0;
public void run()
{
try
{
// 对话内容
talks.load(new FileInputStream("F:\\talk.properties"));
// 客户端发送 "=" 左边的内容
keys=new String[talks.size()];
talks.keySet().toArray(keys);
Socket socket=new Socket(HOST,PORT);
OutputStream ous=socket.getOutputStream();
InputStream ins=socket.getInputStream();
// 接收线程,接收服务器的回应
RecieverThread reciever=new RecieverThread(ins);
reciever.start();
while (!exist)
{
messageCount++;
// 选择一个随机消息
String msg=chooseMessage();
synchronized (ins)
{
// 发送给服务器端
ous.write(msg.getBytes("UTF-8"));
System.out.println("[send]\t"
+messageCount+": "+msg);
// 然后等待接收线程
ins.wait();
}
if (msg.equals("Bye"))
{
break;
}
}
ins.close();
ous.close();
socket.close();
} catch (Exception e)
{
System.out.print("建立新socket出现错误");
e.printStackTrace();
}
}
public String chooseMessage()
{
int index=random.nextInt(keys.length);
String msg=keys[index];
// 如果 10 次就选中 Bye,则重新选择,为了使对话内容多一些
if (messageCount<10&&msg.equalsIgnoreCase("Bye"))
{
return chooseMessage();
}
return msg;
}
// 接收线程
class RecieverThread extends Thread
{
private InputStream ins;
public RecieverThread(InputStream ins)
{
this.ins=ins;
}
@Override
public void run()
{
try
{
String line=null;
BufferedReader r=new BufferedReader(new InputStreamReader(ins,"UTF-8"));
// readLine()会阻塞,直到服务器输出一个 '\n'
while ((line=r.readLine())!=null)
{
System.out.println("[Recieved]: "+line);
synchronized (ins)
{
// 接收到服务器的消息,通知下主线程
ins.notify();
}
if (line.trim().equals("Bye"))
{
exist=true;
break;
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
posted on 2011-04-03 17:04 songqiuming 阅读(560) 评论(0) 编辑 收藏 举报