bio(sockect)或java的nio或netty实现的简单服务器
基于 bio服务器
服务器
服务端开启的时ServerSocket,客户端开启的是Socket,服务端可以通过ServerSocket.accept()获得客户端的Socket,通过ServerSocket.accept().getInputStream即获得输入流。客户端可以通过new Socket(ip,port).getOutputStream获得输出流
public class Server
{
public static void main( String[] args )
{
ServerSocket serverSocket=null;
Socket client=null;
PrintWriter pw=null;
try {
serverSocket=new ServerSocket(8080);
client=serverSocket.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
pw=new PrintWriter(client.getOutputStream());
String request="",response="";
StringBuilder ab=new StringBuilder();
while((request=in.readLine())!=null){
System.out.println(request);
}
response="客户端,奥里给";
pw.write(response);
pw.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
client.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
public class Client {
public static void main(String args[]){
try {
Socket client = new Socket("localhost",8080);
OutputStream os=client.getOutputStream();
os.write("服务器,奥力给".getBytes("utf-8"));//write的后面一定要有关闭流或者shutdownOutput()告知以输入完的操作,否则程序会报错
client.shutdownOutput(); //告诉服务器已发送完毕注意这里不是os.close();---会报Socket is closed,也不是client.close()
//当然,如果不想接受服务端传来的消息,可以使用client.close()断开输出流
BufferedReader bf=new BufferedReader(new InputStreamReader(client.getInputStream()));
String response="";
while((response=bf.readLine())!=null){
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果如下:
这里的socket是短连接。即一次请求应答后就断开了tcp的连接,下面介绍如何使用长连接。(就是死循环socket.accept())参考链接
客户端
public class Client {
public static void main(String args[]){
try {
Socket client = new Socket("localhost",8080);
OutputStream os=client.getOutputStream();
os.write("服务器,奥力给".getBytes("utf-8"));//write的后面一定要有关闭流或者shutdownOutput()告知以输入完的操作,否则程序会报错
client.shutdownOutput(); //告诉服务器已发送完毕注意这里不是os.close();---会报Socket is closed,也不是client.close()
//当然,如果不想接受服务端传来的消息,可以使用client.close()断开输出流
BufferedReader bf=new BufferedReader(new InputStreamReader(client.getInputStream()));
String response="";
while((response=bf.readLine())!=null){
System.out.println(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器:
public class Server
{
static int requestCount=1;
public static void main( String[] args )
{
ServerSocket serverSocket=null;
Socket client=null;
PrintWriter pw=null;
try {
serverSocket=new ServerSocket(8080);
while(true){
client=serverSocket.accept();
new Thread(new Task(client)).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
client.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class Task implements Runnable{
Socket socket=null;
public Task(Socket socket){
this.socket=socket;
}
@Override
public void run() {
BufferedReader in= null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw=new PrintWriter(socket.getOutputStream());
String request="",response="";
StringBuilder ab=new StringBuilder();
while((request=in.readLine())!=null){
System.out.println(request);
}
response="客户端,奥里给 "+requestCount++ +" 次";
pw.write(response);
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行效果如下:
以上是BIO模型的网络,下面写一下NIO模型的服务器
backlog参数对TCP连接建立的影响
套接字编程中listen的第二个参数backlog是什么意思?多大的值合适?我不假思索地回答它表示服务器可以接受的并发请求的最大值
基于java的nio服务器
public class PlainNioServer {
public static void main(String[] args) {
try {
new PlainNioServer().server(9999);
} catch (IOException e) {
e.printStackTrace();
}
}
public void server(int port) throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
for (;;){
try {
selector.select();
} catch (IOException ex) {
ex.printStackTrace();
//handle exception
break;
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server =
(ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_WRITE |
SelectionKey.OP_READ, msg.duplicate());
System.out.println(
"Accepted connection from " + client);
}
if (key.isWritable()) {
SocketChannel client =
(SocketChannel) key.channel();
ByteBuffer buffer =
(ByteBuffer) key.attachment();
while (buffer.hasRemaining()) {
if (client.write(buffer) == 0) {
break;
}
}
client.close();
}
} catch (IOException ex) {
key.cancel();
try {
key.channel().close();
} catch (IOException cex) {
// ignore on close
}
}
}
}
}
}
基于netty的服务器
关于在线聊天服务器可参考连接
服务端
public class NettyServer {
private int port;
public NettyServer(int port) {
this.port=port;
}
public static void main(String[] args) {
new NettyServer(8888).start();
}
private void start() {
EventLoopGroup boss=new NioEventLoopGroup(); //事件循环多线程---接收请求的
EventLoopGroup worker=new NioEventLoopGroup(); //事件循环多线程---处理请求的
ServerBootstrap bootstrap=new ServerBootstrap(); //netty服务器启动的一个驱动类,即初始化服务器配置的
bootstrap.group(boss,worker).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务端收到请求:"+ ByteBuf2String.convertByteBufToString(buf));
/**
* Netty中的消息传递,都必须以字节的形式,以ChannelBuffer为载体传递。
*/
/**
* ByteBuf in;
* in.writeBytes("你收到了吗".getBytes());
*/
ctx.writeAndFlush(Unpooled.copiedBuffer(("ok".getBytes())));
ctx.close();
}
});
}
});
try {
ChannelFuture f= bootstrap.bind(port).sync();
f.addListener(new GenericFutureListener<ChannelFuture>() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
//System.out.println("Netty init over,result:{}"+ future.isSuccess());
}
});
f.channel().closeFuture().sync();
// System.out.println("============5252535353=========");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
worker.shutdownGracefully();
boss.shutdownGracefully();
}
}
}
客户端
public class NettyClient {
public static void main(String[] args) {
new NettyClient().clientStart();
}
private void clientStart() {
EventLoopGroup workers = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(workers)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
final ChannelFuture f = ctx.writeAndFlush(Unpooled.copiedBuffer(("HelloNetty".getBytes())));
System.out.println("客户端发送请求:"+"HelloNetty");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端收到响应:"+ ByteBuf2String.convertByteBufToString(buf));
} finally {
ReferenceCountUtil.release(msg);
}
}
});
}
});
try {
//System.out.println("start to connect...");
ChannelFuture f = b.connect("127.0.0.1", 8888).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workers.shutdownGracefully();
}
}
}
还有一个工具类【bytebuff转string】
public class ByteBuf2String {
public static String convertByteBufToString(ByteBuf buf) {
String str;
if(buf.hasArray()) { // 处理堆缓冲区
str = new String(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes());
} else { // 处理直接缓冲区以及复合缓冲区
byte[] bytes = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), bytes);
str = new String(bytes, 0, buf.readableBytes());
}
return str;
}
}
效果如下: