I've been studying the book Pro Java 7 NIO.2 to get a better understanding of the NIO package, and wanted to work on some networking related code to better my understanding of how netty works in the background. The over-all error makes sense, but why the error is being thrown is beyond my comprehension.
java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
The first thing that I did was make sure that none of my code was importing anything from the sun packaging, and that everything was in-fact using the java.nio package. Everything seems to check out.
This error is thrown when I attempt to connect a client to the server, but what really bothers me is the general fact that it's trying to type-cast to a ServerSocketChannel and not just a SocketChannel, which leads me to believe that the Server is confused.
I do apologise in advance for a wall of code down below, but as everyone always requests that I post a running example I plan to do just that. This is three class files small.
TcpProcessor.java
package net.ogserver.proto.tcp;
import java.io.IOException;
import java.net.InetSocketAddress;
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 net.ogserver.proto.connections.Connection;
public class TcpProcessor implements Runnable {
public static int tcpPort;
public void run() {
try (Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
if((serverSocket.isOpen()) && (selector.isOpen())) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(tcpPort));
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server has started and is waiting for connections...");
while(!Thread.interrupted()) {
selector.select();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while(keys.hasNext()) {
SelectionKey key = (SelectionKey) keys.next();
keys.remove();
if(!key.isValid()) {
continue;
}
if(key.isAcceptable()) {
processIncomingConnection(key, selector);
} else if(key.isReadable()) {
//processIncomingData(key);
} else if(key.isWritable()) {
//pushOutgoingData(key);
}
}
}
} else {
System.err.println("There was an issue constructing the socket.");
}
} catch(IOException e) {
e.printStackTrace();
}
}
private void processIncomingConnection(SelectionKey selectionKey, Selector selector) throws IOException {
ServerSocketChannel serverSocket = (ServerSocketChannel)selectionKey.channel();
SocketChannel clientSocket = serverSocket.accept();
clientSocket.configureBlocking(false);
System.out.println("Incoming connection from " + clientSocket.getRemoteAddress());
selectionKey.attach(new Connection(selectionKey));
clientSocket.register(selector, SelectionKey.OP_READ);
}
}
Connection.java
package net.ogserver.proto.connections;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
public class Connection {
private SelectionKey selectionKey;
private SocketChannel clientSocket;
private ByteBuffer networkInputBuffer;
private ByteBuffer networkOutputBuffer;
public Connection(SelectionKey selectionKey) {
this.selectionKey = selectionKey;
this.clientSocket = (SocketChannel)selectionKey.channel();
this.networkInputBuffer = ByteBuffer.allocate(1024);
this.networkOutputBuffer = ByteBuffer.allocate(8192);
}
public SelectionKey getSelectionKey() {
return selectionKey;
}
public ByteBuffer getInputBuffer() {
return networkInputBuffer;
}
public ByteBuffer getOutputBuffer() {
return networkOutputBuffer;
}
public SocketChannel getChannel() {
return clientSocket;
}
}
Server.java
package net.ogserver.proto;
import net.ogserver.proto.tcp.TcpProcessor;
public class Server {
private Thread tcpProcessor;
public Server(int port) {
TcpProcessor.tcpPort = port;
tcpProcessor = new Thread(new TcpProcessor());
tcpProcessor.start();
}
public static void main(String[] args) {
new Server(5055);
}
}
There error occurs when TcpProcessor#processIncomingConnection is called, which invokes the creation of a new Connection instance. The line throwing this error is a direct quote from the book, and I've taken a look at a few other NIO servers and the line is exactly the same (Minus some naming) in most of them.
this.clientSocket = (SocketChannel)selectionKey.channel();
Any help would be greatly appreciated, full console output for those who want it:
Server has started and is waiting for connections...
Incoming connection from /127.0.0.1:53221
Exception in thread "Thread-0" java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
at net.ogserver.proto.connections.Connection.<init>(Connection.java:17)
at net.ogserver.proto.tcp.TcpProcessor.processIncomingConnection(TcpProcessor.java:60)
at net.ogserver.proto.tcp.TcpProcessor.run(TcpProcessor.java:37)
at java.lang.Thread.run(Thread.java:745)
I should probably add that the implementation of typecasting socketchannel form the selectionkey.channel() comes straight from the JavaDocs -- http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2
You're passing the wrong SelectionKey to new Connection(...). You're passing the server socket's key. The key you should pass is the accepted socket's key, which is the result of socketChannel.register(), on the next line.
The sun.nio.ch.* classes appear to contain some implementations of interfaces in the java.nio.* package(s); the crossover to the different package occurs in the implementation classes you're using. No great mystery there.
By looking at the source for sun.nio.ch.ServerSocketChannelImpl, I see that it implements java.nio.channels.ServerSocketChannel, not java.nio.channels.SocketChannel. It's a channel implementation, not a socket implementation. Both the ServerSocketChannel and SocketChannel (in java.nio.channels) extend AbstractSelectableChannel, but they are siblings in the inheritance hierarchy, not ancestor/descendant.
Hope that helps.
Related
I have created a simple class which sends a string to a server, both communicate using Java Sockets API. The server reads what the client have sent, and responds with another string. But the client can not read that response.
This is the client class:
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8181);
socket.getOutputStream().write("Hello".getBytes());
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.close();
}
}
And this is the server class:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8181);
while (true) {
Socket socket = serverSocket.accept();
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.getOutputStream().write("Hi!".getBytes());
}
}
}
I imagine that the problem may be in the client execution flow, because I don`t know how canI do it wait for a server response. In other words, how to implement a client able to read the server response?
You aren't closing the sockets.
The server is attempting to read until end of stream and then send a reply. End of stream only happens when the peer closes the connection, so it won't be possible to send a reply even after you fix (1). You need to read a message, whatever that means in your application protocol.
You need to flush or close the outputstream.
i want to know the functionality of sockets in java. when i am creating some http-server i can use some ready to use sockets for secure and non-secure communication between two parties. but i never installed tomcat to my project, so my question is: how can java create a tcp / ip connection without a web-server? Can someone post me some link to clear this question?
In my case i used this to create a SSLSocket:
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocketFactory;
public class MainClass {
public static void main(String args[]) throws Exception {
SSLServerSocketFactory ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
ServerSocket ss = ssf.createServerSocket(5432);
while (true) {
Socket s = ss.accept();
PrintStream out = new PrintStream(s.getOutputStream());
out.println("Hi");
out.close();
s.close();
}
}
}
Thank u a lot,
Mira
I read some materials about ServerSocket and tried to listen on port 80 and print for example InetAddress of website which I was opening in web browser but my program couldn't do this. My code:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Site implements Runnable {
private int port;
Site(int port){
this.port = port;
}
public void run() {
try {
ServerSocket server = new ServerSocket(port);
while(true){
Socket socket = server.accept();
System.out.println(socket.getInetAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
Thread thread = new Thread(new Site(80));
thread.start();
}
}
When I run my program I am only one time in the while loop and the program doesn't print System.out.println(socket.getInetAddress()) and as the result when I open my web browser and visit http sites I don't see any output. Do you know what I am doing wrong? Do you know any other ways to print InetAddress for currently open website? Any materials will by appreciate.
I can't comment without proper reputation so forgive me for throwing everything out here:
you might already have something listening on port 80
you might be running on a version of linux that restricts non root process binding to ports above 1024
you might be blocked by a software firewall
I have made a simple ActiveMQ application.
It listens to a queue. If a message comes, print out the dataId
Here is the code:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
public class MQ implements MessageListener {
private Connection connection = null;
private Session session = null;
private Destination destination = null;
private void errorOnConnection(JMSException e) {
System.out.println("MQ is having problems. Exception::"+ e);
}
private void init() throws JMSException {
String BROKER_URL = "failover:(tcp://myQueue001:61616,tcp://myQueue002:61616)?randomize=false";
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
connection = connectionFactory.createConnection("user", "password");
connection.setExceptionListener(
new ExceptionListener() {
#Override public void onException(JMSException e) {
errorOnConnection(e);
}
});
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("myQueue");
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(this);
}
public boolean start() {
try {
if(connection==null )
init();
connection.start();
} catch (Exception e) {
System.out.println("MQListener cannot be started, exception: " + e);
}
return true;
}
#Override
public void onMessage(Message msg) {
try {
if(msg instanceof MapMessage){
MapMessage m = (MapMessage)msg;
int dataId = m.getIntProperty("dataId");
System.out.println(dataId);
}
} catch (JMSException e) {
System.out.println("Got an exception: " + e);
}
}
public static void main(String[] args) {
MQ mq = new MQ();
mq.start();
}
}
It works fine and does what it is meant to accomplish.
However, the problem is that it can run only for several days. After several days, it just quits silently without any exceptions or error.
The queue I am listening to is from 3rd party. From a guy there, the queue sometimes will be closed or restarted or interrupted.
But I think even if that happen, the default ActiveMQ settings will handle it by consistently reconnect to it, right? (according to http://activemq.apache.org/cms/configuring.html)
So any other possible causes which lead my code to quitting silently?
Depends on bit on your version. Since you are not doing anything yourself to keep the application running but instead depending on the ActiveMQ code to keep at least one non-deamon thread running. In some ActiveMQ versions the client wasn't always doing this so your application could quite while a failover was occurring. Best bet is to switch to v5.8.0 which I believe had some fixes for this.
You could add some polling code in main to read something from console or what not to ensure that the client stays up until you are sure you want it to go down.
I was wondering if i could get help making or finding a program that has the ability to send keyboard presses and receive them on another computer. I want to use this to play multiplayer flash-player games with friends across computers. I know there are some programs out there like "logmein" but both users cannot use the keyboard at the same time. (When i press a key the computer user cannot press a key at the same time because it wont respond.) I only know java and I am quite novice at it. Im guessing if i need to write it ill have to send the information through a port or onto a web-server. I would like to know your opinions and suggestions for this program, thanks guys.
Basically what you are looking for is a chatroom program? Have you tried looking into mIRC?
mIRC is a free internet relay chat. What exactly are the requirements for the program? Is there a certain size that it must be? Are these flash games that you and your friends are playing taking up your full computer screen?
Building a program would require a web-server(any computer with internet access would do), and you would have to open the ports on your network to allow the traffic to go through.
A basic server in java would look something like this:
Please note that after the first connection this "server" will close the connection.
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Server
{
private static ServerSocket serverSocket;
private static Socket clientSocket;
private static BufferedReader bufferedReader;
private static String inputLine;
public static void main(String[] args)
{
// Wait for client to connect on 63400
try
{
serverSocket = new ServerSocket(63400);
while(true){
clientSocket = serverSocket.accept();
// Create a reader
bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Get the client message
while((inputLine = bufferedReader.readLine()) != null)
{System.out.println(inputLine);}
serverSocket.close();
System.out.println("close");
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
And a client would almost be the same:
import java.net.Socket;
import java.io.PrintWriter;
public class client
{
private static Socket socket;
private static PrintWriter printWriter;
public static void main(String[] args)
{
try
{
//change "localhost" to the ip address that the client is on, and this number to the port
socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
If I am not mistaken printWriter is a 16-bit operation, and in order to reduce lag, if you were just sending text then you might want to use printStream(). I believe that this might be a bit quicker.