Browse Source

Started switching to netty.io

Everything is a mess, but at least it is something...
Tankernn 8 years ago
parent
commit
aaabf19aa9

+ 6 - 0
pom.xml

@@ -30,6 +30,12 @@
 			<artifactId>reflections</artifactId>
 			<version>0.9.10</version>
 		</dependency>
+		<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
+		<dependency>
+			<groupId>io.netty</groupId>
+			<artifactId>netty-all</artifactId>
+			<version>4.1.8.Final</version>
+		</dependency>
 	</dependencies>
 
 	<build>

+ 40 - 0
src/main/java/eu/tankernn/chat/client/ChatClientHandler.java

@@ -0,0 +1,40 @@
+package eu.tankernn.chat.client;
+
+import javax.swing.DefaultListModel;
+
+import eu.tankernn.chat.common.InfoPacket;
+import eu.tankernn.chat.common.MessagePacket;
+import eu.tankernn.chat.common.MessagePacket.MessageType;
+import eu.tankernn.chat.common.Packet;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+public class ChatClientHandler extends ChannelInboundHandlerAdapter {
+	private ChatWindow chatWindow;
+
+	public ChatClientHandler(ChatWindow chatWindow) {
+		this.chatWindow = chatWindow;
+	}
+
+	@Override
+	public void channelRead(ChannelHandlerContext ctx, Object fromServer) {
+	    System.out.println(fromServer);
+	    if (fromServer instanceof MessagePacket) {
+			MessagePacket mess = ((MessagePacket) fromServer);
+			chatWindow.chat.log(mess);
+		} else if (fromServer instanceof InfoPacket) {
+			InfoPacket info = (InfoPacket) fromServer;
+
+			chatWindow.infoLabel.setText("<html>" + info.toString().replace("\n", "<br>"));
+
+			DefaultListModel<String> model = new DefaultListModel<String>();
+			for (String user : info.usersOnline)
+				model.addElement(user);
+
+			chatWindow.userList.setModel(chatWindow.model);
+		} else if (fromServer instanceof String) {
+			chatWindow.chat.log(new MessagePacket((String) fromServer, MessageType.NORMAL));
+		}
+	    ctx.close();
+	}
+}

+ 92 - 76
src/main/java/eu/tankernn/chat/client/ChatWindow.java

@@ -9,14 +9,10 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
-import java.io.EOFException;
 import java.io.File;
-import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.PrintWriter;
-import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.net.SocketTimeoutException;
 import java.util.ArrayList;
 
 import javax.swing.DefaultListModel;
@@ -31,15 +27,28 @@ import javax.swing.ListSelectionModel;
 import javax.swing.WindowConstants;
 import javax.swing.border.EmptyBorder;
 
-import eu.tankernn.chat.common.InfoPacket;
 import eu.tankernn.chat.common.MessagePacket;
 import eu.tankernn.chat.common.MessagePacket.MessageType;
+import eu.tankernn.chat.common.Packet;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.serialization.ClassResolvers;
+import io.netty.handler.codec.serialization.ObjectDecoder;
+import io.netty.handler.codec.string.StringEncoder;
 
 @SuppressWarnings("serial")
-public class ChatWindow extends JFrame implements ActionListener, Runnable, KeyListener {
+public class ChatWindow extends JFrame implements ActionListener, KeyListener {
 	Thread getMessages;
 	static File confFile = new File("client.properties");
 
+	EventLoopGroup workerGroup = new NioEventLoopGroup();
+
 	String adress, username;
 	ArrayList<String> lastMess = new ArrayList<String>();
 	int port, messIndex = 0;
@@ -123,40 +132,70 @@ public class ChatWindow extends JFrame implements ActionListener, Runnable, KeyL
 		}
 	}
 
-	void connect(String address, int port, String username) {
-		chat.log(new MessagePacket("Connecting to " + address + " on port " + port + ".", MessageType.INFO));
-		if (getMessages != null)
-			getMessages.interrupt();
-
-		try {
-			so.close();
-			objIn.close();
-			out.close();
-		} catch (NullPointerException ex) {
-			// Nothing
-		} catch (IOException ex) {
-			chat.log(new MessagePacket(ex.toString(), MessageType.ERROR));
-		}
-
+	// void connect(String address, int port, String username) {
+	// chat.log(new MessagePacket("Connecting to " + address + " on port " +
+	// port + ".", MessageType.INFO));
+	// if (getMessages != null)
+	// getMessages.interrupt();
+	//
+	// try {
+	// so.close();
+	// objIn.close();
+	// out.close();
+	// } catch (NullPointerException ex) {
+	// // Nothing
+	// } catch (IOException ex) {
+	// chat.log(new MessagePacket(ex.toString(), MessageType.ERROR));
+	// }
+	//
+	// try {
+	// so = new Socket();
+	// so.connect(new InetSocketAddress(address, port));
+	// objIn = new ObjectInputStream(so.getInputStream());
+	// out = new PrintWriter(so.getOutputStream(), true);
+	// } catch (SocketTimeoutException ex) {
+	// chat.log(new MessagePacket("Could not connect to server. (Connection
+	// timed out!)", MessageType.ERROR));
+	// return;
+	// } catch (IOException e) {
+	// chat.log(new MessagePacket(e.toString(), MessageType.ERROR));
+	// return;
+	// }
+	//
+	// send(username); // First packet sent to server sets username
+	//
+	// getMessages = new Thread(this);
+	// getMessages.start();
+	//
+	// write.setEnabled(true);
+	// }
+
+	protected void connect(String address, int port, String username) {
 		try {
-			so = new Socket();
-			so.connect(new InetSocketAddress(address, port));
-			objIn = new ObjectInputStream(so.getInputStream());
-			out = new PrintWriter(so.getOutputStream(), true);
-		} catch (SocketTimeoutException ex) {
-			chat.log(new MessagePacket("Could not connect to server. (Connection timed out!)", MessageType.ERROR));
-			return;
-		} catch (IOException e) {
-			chat.log(new MessagePacket(e.toString(), MessageType.ERROR));
-			return;
+			Bootstrap b = new Bootstrap();
+			b.group(workerGroup);
+			b.channel(NioSocketChannel.class);
+			b.option(ChannelOption.SO_KEEPALIVE, true);
+			b.handler(new ChannelInitializer<SocketChannel>() {
+				@Override
+				public void initChannel(SocketChannel ch) throws Exception {
+					ch.pipeline().addLast("decoder",
+							new ObjectDecoder(ClassResolvers.weakCachingResolver(Packet.class.getClassLoader())));
+					ch.pipeline().addLast("encoder", new StringEncoder());
+					ch.pipeline().addLast("handler", new ChatClientHandler(ChatWindow.this));
+				}
+			});
+
+			// Start the client.
+			ChannelFuture f = b.connect(address, port).sync();
+
+			// Wait until the connection is closed.
+			f.channel().closeFuture().sync();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		} finally {
+			workerGroup.shutdownGracefully();
 		}
-
-		send(username); // First packet sent to server sets username
-
-		getMessages = new Thread(this);
-		getMessages.start();
-
-		write.setEnabled(true);
 	}
 
 	@Override
@@ -165,43 +204,20 @@ public class ChatWindow extends JFrame implements ActionListener, Runnable, KeyL
 			connect(adress, port, username);
 	}
 
-	@Override
-	public void run() {
-		try {
-			getMessages();
-		} catch (EOFException eof) {
-			chat.log(new MessagePacket(eof.toString() + " Disconnected from host.", MessageType.ERROR));
-		} catch (ClassNotFoundException cnf) {
-			chat.log(new MessagePacket(
-					"The message recieved from the server could not be understood. Are you using the right version?",
-					MessageType.ERROR));
-		} catch (IOException e) {
-			chat.log(new MessagePacket(e.toString(), MessageType.ERROR));
-		}
-	}
-
-	public void getMessages() throws IOException, ClassNotFoundException {
-		while (!getMessages.isInterrupted()) {
-			Object fromServer = objIn.readObject();
-			if (fromServer instanceof MessagePacket) {
-				MessagePacket mess = ((MessagePacket) fromServer);
-				chat.log(mess);
-			} else if (fromServer instanceof InfoPacket) {
-				InfoPacket info = (InfoPacket) fromServer;
-
-				infoLabel.setText("<html>" + info.toString().replace("\n", "<br>"));
-
-				model = new DefaultListModel<String>();
-				for (String user : info.usersOnline)
-					model.addElement(user);
-
-				userList.setModel(model);
-			} else if (fromServer instanceof String) {
-				chat.log(new MessagePacket((String) fromServer, MessageType.NORMAL));
-			} else
-				throw new ClassNotFoundException();
-		}
-	}
+//	@Override
+//	public void run() {
+//		try {
+//			getMessages();
+//		} catch (EOFException eof) {
+//			chat.log(new MessagePacket(eof.toString() + " Disconnected from host.", MessageType.ERROR));
+//		} catch (ClassNotFoundException cnf) {
+//			chat.log(new MessagePacket(
+//					"The message recieved from the server could not be understood. Are you using the right version?",
+//					MessageType.ERROR));
+//		} catch (IOException e) {
+//			chat.log(new MessagePacket(e.toString(), MessageType.ERROR));
+//		}
+//	}
 
 	@Override
 	public void keyPressed(KeyEvent eKey) {
@@ -241,7 +257,7 @@ public class ChatWindow extends JFrame implements ActionListener, Runnable, KeyL
 	@Override
 	public void keyTyped(KeyEvent arg0) {
 	}
-	
+
 	public boolean isConnected() {
 		return so.isConnected() && !so.isClosed();
 	}

+ 20 - 0
src/main/java/eu/tankernn/chat/server/ChatServerHandler.java

@@ -0,0 +1,20 @@
+package eu.tankernn.chat.server;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+public class ChatServerHandler extends ChannelInboundHandlerAdapter {
+	@Override
+	public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
+		// Discard the received data silently.
+		((ByteBuf) msg).release(); // (3)
+	}
+
+	@Override
+	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
+		// Close the connection when an exception is raised.
+		cause.printStackTrace();
+		ctx.close();
+	}
+}

+ 44 - 1
src/main/java/eu/tankernn/chat/server/Server.java

@@ -16,6 +16,18 @@ import java.util.logging.LogManager;
 import java.util.logging.Logger;
 
 import eu.tankernn.chat.common.MessagePacket;
+import eu.tankernn.chat.common.Packet;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.serialization.ClassResolvers;
+import io.netty.handler.codec.serialization.ObjectDecoder;
+import io.netty.handler.codec.string.StringDecoder;
 
 public class Server {
 	private static Thread clientListener;
@@ -76,7 +88,7 @@ public class Server {
 		OPClient = new LocalClient();
 
 		log.fine("Starting client listener thread...");
-		clientListener = new Thread(Server::listenClients);
+		clientListener = new Thread(Server::run);
 		clientListener.start();
 
 		log.info("Server started successfully!");
@@ -106,6 +118,37 @@ public class Server {
 		}
 	}
 
+	private static void run() {
+		EventLoopGroup bossGroup = new NioEventLoopGroup();
+		EventLoopGroup workerGroup = new NioEventLoopGroup();
+		try {
+			ServerBootstrap b = new ServerBootstrap();
+			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
+					.childHandler(new ChannelInitializer<SocketChannel>() {
+						@Override
+						public void initChannel(SocketChannel ch) throws Exception {
+							ch.pipeline().addLast("decoder", new StringDecoder());
+							ch.pipeline().addLast("encoder", new ObjectDecoder(ClassResolvers.weakCachingResolver(Packet.class.getClassLoader())));
+							ch.pipeline().addLast("handler", new ChatServerHandler());
+						}
+					}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
+
+			// Bind and start to accept incoming connections.
+			ChannelFuture f = b.bind(port).sync();
+
+			// Wait until the server socket is closed.
+			// In this example, this does not happen, but you can do that to
+			// gracefully
+			// shut down your server.
+			f.channel().closeFuture().sync();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		} finally {
+			workerGroup.shutdownGracefully();
+			bossGroup.shutdownGracefully();
+		}
+	}
+
 	public static Optional<Channel> getChannelByName(String name) throws NullPointerException {
 		return getChannels().stream().filter(c -> c.name.equals(name)).findFirst();
 	}