I am trying to establish a tcp connection through which I want to share data from one webform(jsp page) to another web page with same content.
below is servlet which gets called when clicking button on jsp page. As I checked the port which trying to connect is in listening state and from servlet it should get redirected to receiver form but it just keeps loading.
but program is getting stuck at Socket insocket = socket.accept(); this line.
I searched in other resources as well but got answer as "Socket.accept() hangs by design until a client connects to the port that is being waited on, in this case, port 8189. Your program is working fine"
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String first = request.getParameter("first_name");
String last = request.getParameter("last_name");
String name = first + " " + last;
PrintWriter out = response.getWriter();
byte buffer[] = new byte[10240];
buffer = name.getBytes();
try {
ServerSocket socket = new ServerSocket(4333);
Socket insocket = socket.accept();
OutputStream outSocket = insocket.getOutputStream();
outSocket.write(buffer);
response.sendRedirect("receiver.jsp");
} catch (java.net.ConnectException e) {
System.out.println("server application not started.....");
}
}
The recommended way to establish a socket-like connection between a web browser or client and a web server is to use WebSockets. This causes the connection used for the HTTP request / response to be taken over for bidirectional socket communication. It is a widely supported extension to the HTTP protocol.
If you want to connect two or more web browsers or web clients via the web server, you need to establish WebSockets between each browser server, and then the server needs to route the information from between the server ends of the WebSockets.
The implementation details will depend on the technology stack used on the client and server sides. You could start by reading the following:
The Wikipedia WebSocket article.
A Guide to the Java API for WebSocket
RFC 6455 - The WebSocket Protocol
They way you are trying to do it looks like it won't work. Even if it does kind of work, there will be issues with managing the connections that you have established ... leading to resource leakage, problems with recycling ports, etcetera. And then you need to deal with potential security issues; e.g. establishing that the client that connects to the ServerSocket port you are listening on is not some interloper.
Related
Intro
My code can process all bytes that are sent to a server and decide whether or not to let them go through and eventually send responses. I would like to use this to use the server as web server, web socket server and tcp server in one.
Although my code is written for Minecraft, I am not asking this on a Minecraft forum because answering this question doesn't require any prior knowledge about Minecraft or its codebase.
All you need to know about Minecraft
Minecraft is a Java game that can be played online. When it is being played online, there is a server that opens a ServerSocket and all players have their own client that opens a Socket that will communicate with the ServerSocket of the server.
Anyone can create a Minecraft server and install server-side modifications on their server (for those who know Minecraft, these are usually called plug-ins). My application is such a server-side modification. Most Minecraft servers are being hosted by Minecraft host companies. The owners of the servers have some kind of access to the part of the host computer that manages the server files.
Goal
The goal of my modification is to let the Minecraft server serve more clients than just the Minecraft clients. I would like the same server to also work as web server (for http and https requests) as well as (secure) web socket server and tcp server.
Why no multiple server sockets
The most common solution would be to just create a ServerSocket for the other server types and assign a different port to all of them. However, that is not an option in my case. Most hosts forbid you to open other ports or ask extra money for it. So I need to do it all with just the Minecraft ServerSocket.
What I achieved so far
So far, I have managed to let all bytes that are sent to the minecraft server first go through my code. My code can choose whether or not to let the bytes continue to the Minecraft server code. It can also send responses on its own without the need to inform the Minecraft server code at all.
In principle, what I have managed to do is sufficient to accomplish my goal, but I would like some help with how to continue. I will explain below what I have and have not accomplished so far.
The first byte that is sent by a Minecraft client to the server is always the same, namely 16. This is great because it allows me to easily distinguish Minecraft clients from web browsers and tcp clients.
HTTP requests and websocket connections always start with the same byte, namely 71. HTTPS and secure websockets always start with the byte 22. The TCP connections I was talking about will be sent by my own applications, so I can choose exactly what bytes they will send and I can simply program my modification to respond to that.
I managed to distinguish http requests and websocket connections by their connection property. Http requests always send 'Connection: keep-alive' while websocket connections always send 'Connection: upgrade'. (Although some browsers do the k, a and u in uppercase and others do not.)
Handling normal http requests wasn't very hard to do. Handling TCP connections won't be hard either because I will control everything. But I have issues with the remaining connection types:
Problems I need help with
The web socket protocol is quite large and I would prefer not to handle it completely with only my code. (I tried this before, but I kept having problems with the parts that were rarely used and thus not tested.) So I would like to use some library that allows me to only worry about the payload rather than the entire protocol. Unfortunately, web socket libraries generally want to create the ServerSocket, which is not possible in my case. So does anyone have advice on what to do here?
I haven't found any info on how to read https requests properly. Could someone tell me where to look for the details of this protocol or provide a nice link?
For secure web sockets, I will face the same problems as with the 'normal' web socket connections after I find out how to read the requests.
Code
All my code so far can be found at https://github.com/knokko/Multi-Purpose-Server. The most interesting part is probably the part where my code gets the opportunity to process all bytes before they arrive at the Minecraft code, that code is shown below.
Short question(s)
For those who didn't understand exactly what my question (you could see it as 2 questions that are strongly related) is:
-How I should read https requests and secure web socket handshakes?
-Does anyone know a library that can handle web socket input that doesn't require to create the ServerSocket itself?
// This channel handler will be registered for every connection client that will
// inspect
// any message before it reaches the Minecraft code.
pipeline.addFirst("multipurpose_handler_inspector", new ChannelInboundHandlerAdapter() {
private boolean deactivated;
private ChannelListener listener;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//super.channelRead will send the content to the minecraft code
try {
if (!deactivated) {
ByteBuf message = (ByteBuf) msg;
if (listener != null) {
listener.read(ctx, message);
} else {
byte firstByte = message.getByte(0);
// All Minecraft connections start with the byte 16
if (firstByte == 16) {
deactivated = true;
super.channelRead(ctx, msg);
}
// All insecure web connections start with the byte 71
else if (firstByte == 71) {
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
WebHandler.Type type = WebHandler.determineConnectionType(data);
if (type == WebHandler.Type.HTTP) {
listener = new HTTPListener();
listener.readInitial(ctx, message);
} else if (type == WebHandler.Type.WEBSOCKET) {
// TODO Find a nice way to handle web socket connections
listener = new WebSocketListener();
listener.readInitial(ctx, message);
} else {
deactivated = true;
super.channelRead(ctx, msg);
}
}
// All secure web connections start with the byte 22
else if (firstByte == 22) {
// TODO implement the secure web protocols and find a way to read this stuff
// and find the difference
System.out.println(
"We are dealing with a secure websocket or https connection");
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
System.out.println(new String(data));
}
// My applications
else if (firstByte == 31) {
listener = new TCPListener();
listener.readInitial(ctx, message);
} else {
System.out.println("Unknown connection type");
deactivated = true;
super.channelRead(ctx, msg);
}
}
} else {
super.channelRead(ctx, msg);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
If you can ALWAYS identify the Minecraft traffic, your best bet might be to run an apache/httpd and/or tomcat server on the same box and forward all non-Minecraft traffic to it. If you do this, the HTTPS stuff might just be a matter of correctly configuring the http server for https traffic.
You may have to configure your code as an http proxy--in fact (Just thought of this) you might want to go out and look for an open source http proxy and just tweak it with your code to extract Minecraft traffic and forward it before doing the rest of the proxy stuff.
I wouldn't do the HTTPs stuff from scratch, it's not terribly difficult but I'd call it non-trivial.
Oh and if your problem is "differentiating Minecraft HTTPS traffic from other HTTPS connections on the same port" I can't help except to say that this might be a good subject for your question :)
I'm writing a ServerSocket in java. I want to send some special content to client connecting to me through telnet. I want to send other content if he/she connects through Browser and etc. Is there any way to find out that user is connecting to me with telnet?
My code :
public void handleConnection(Socket socket) throws IOException {
String author = "Ehsan Akbari";
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
if(checkoutClientType(socket)=="telnet")
out.println("You are connecting through telnet :\)");
else
out.println("You are not connecting through telnet :|");
}
What should be the definition of checkoutClientType(Socket s);?
You cannot tell what program is on the other side of a socket by examining the socket itself. There is no test or operation you can perform on the socket that will distinguish the client program.
The only hope is to examine the data being transmitted to see if it matches an expected pattern, but for that you have to have some data transmitted. It might be possible to tell if the remote is telnet if you were to send a Telnet Protocol command such as AYT (Are You There), but that would probably not sit well with a different client such as a browser.
If you were able to proxy the data between the client and a handling process or thread and examine it you might be able to eventually determine if it was Telnet, but probably not, and probably not immediately.
I am currently trying to make an application that will send messages to a server using one port, but will receive messages on another port. However, based on tutorials I have followed, it looks like the act of connecting to the server is where ports come into play and my client is receiving and sending messages on the same port. How do I make it so it sends on one port but receives on the other?
Here is the code that I think is relevant from the client side (I put some stuff that seems unrelated because I think they are things that would be altered by receiving on one port but sending on another, and ignore the comment about replacing inetaddress, that is just me working on implementing this in a gui):
public void startRunning(){
try{
connectToServer();
setupStreams();
whileChatting();
}catch(EOFException eofException){
showMessage("\n Client terminated connection");
}catch(IOException ioException){
ioException.printStackTrace();
}finally{
closeStuff();
}
}
//connect to server
private void connectToServer() throws IOException{
showMessage("Attempting connection... \n");
connection = new Socket(InetAddress.getByName(serverIP), 480);//replace serverIP with ipTextField.getText or set serverIP to equal ipTextField.getText? Same with port number.
showMessage("Connected to: " + connection.getInetAddress().getHostName() );
}
//set up streams to send and receive messages
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
showMessage("\n Streams are good! \n");
}
//while talking with server
private void whileChatting() throws IOException{
ableToType(true);
do{
try{
message = (String) input.readObject();
showMessage("\n" + message);
}catch(ClassNotFoundException classNotfoundException){
showMessage("\n Don't know that object type");
}
}while(!message.equals("SERVER - END"));
}
//send messages to server
private void sendMessage(String message){
try{
output.writeObject("CLIENT - " + message);
output.flush();
showMessage("\nCLIENT - " + message);
}catch(IOException ioException){
messageWindow.append("\n something messed up ");
}
}
//change/update message window
private void showMessage(final String m){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
messageWindow.append(m);
}
}
);
}
EDIT/UPDATE: To help clarify some things, here is some more information. The device that sends the first message is connected to a sensor, and it sends information when that sensor detects something to the other device. The receiving device sends a message back on a different port telling the original sending device how to respond. Lets name these two devices the "reporter-action taker" and the "decision maker-commander".
If you want to use TCP/IP sockets you can't use a a socket to send and another to read. That's not what they are for.
If you use a centralized distributed algorithm (server/client communication) you have to set the server to listen on a single socket port with the ServerSocket class: then the server tries to accept clients through that socket.
Example:
ServerSocket listener = new ServerSocket(Port)
While (true) {
new Clienthandler(listener.accept());
}
The server will listen on that port, and when a client tries to connect to that port if it is accepted the server launches its handler. On this handler constructor the Socket object used on the client is received on an argument and can then be used to get the writers and the readers. The reader on this handler class will be the writer on the client class and vice-versa, maybe that's what you were looking for.
Your question about using two ports in this manner is a bit strange. You state that you have a client and a server and that they should communicate on different ports.
Just to clarify picture the server as a hanging rack for jackets with several hooks in a row. Each port the server listened on represents a hook. When it comes to the client server relationship the client or jacket knows where to find its hook, however the hook is blind and have no idea where to find jackets.
Now, the client selects a port or a hook and connects to it. The connection is like a pipeline with two pipes. One for the client to deliver data to the server with and the other to send data from the server back to the client. When the connection is established data can be transferred both ways. This means that we only need one port open on the server to send data both from the client to the server and in the opposite direction.
The reason for only having one open port open on the server for the clients to connect to is that holding an open port for connections is hard to do on a regular client computer. The normal desktop user will be behind several firewalls blocking incoming connections. If that wasn't the case the client would probably be hacked senseless from malicious viruses.
Moving on with the two port solution we could not call this a client server connection per say. It would be more like a peer to peer connection or something like that. But if this is what you want to do, the application connecting first would have to start by telling the other application what ip and port to use for connecting back, it should probably also want to give some kind of token that are to be used to pair the new incoming connection when connecting back.
You should take note that making such an implementation is not a good idea most of the time as it complicates things a whole lot for simple data transfer between a client and server application.
I'm looking for verification on the following:
In order to find out whether a server is up, I'm supposed to
establish a TCP connection to the host:port combination of the server given to me.
And in that case, "if a connection is established, then the service is up, otherwise -
if the connection is refused, the service is down".
So, should i be satisfied that the server is up when getRemoteSocketAddress() of Socket returns an object and not null? That is, does the following code always print the accurate info to the console?
Socket clientSocket = new Socket(hostName, port);
System.out.println("To console: The server is " + (clientSocket.getRemoteSocketAddress()==null?"down.":"up.") );
To me, it does. However, i haven't practical info on these things and won't make sure without a second opinion.
Note: I'm aware that, the server being up doesn't necessarily mean that it is accepting and processing requests. That goes by exchanging some greetings to see/hear one another on who's who and go from there based on the protocol in between. However, these aren't relevant on this one.
TIA
You would not even need to call
clientSocket.getRemoteSocketAddress();
because the constructor call from:
Socket clientSocket = new Socket(hostName, port);
will try to connect to the socket and will throw an IOException if it fails to do so. So I would rather do this:
public boolean hostUp(String hostName, int port) {
try {
Socket clientSocket = new Socket(hostName, port);
return true;
} catch(IOException e) {
return false;
}
}
That should do the trick.
Establishing TCP connection is a health-check at level 3 (OSI). It tells you that the service is up and running and listening on the port. However, it doesnt tells you anything about upper layers. For instance, if you use the server to serve http objects, you could do with http GET /sample.file on top of the established tcp connection. Alternatively, you could use this server for REST API, and then not only would you like to see 200 OK response from http layer, but maybe something more sophisticated in the response body.
I am trying to open a basic connection to an HL7 server where I send a request and get the ACK response. This will be done continuously.
If this is being done continuously, when do I close the socket? Am I implementing this correctly, in this case?
If I close the socket, how do I open it again? The javadocs for ConnectionHub indicates the following:
attach(java.lang.String host, int port, Parser parser,
java.lang.Class<? extends LowerLayerProtocol> llpClass)
Returns a Connection to the given address, opening this Connection if necessary.
However, in real life, it will not open a new connection if it was already closed.
Patient patient = appt.getPatient();
Parser parser = new GenericParser();
Message hl7msg = parser.parse(wlp.getORMString(appt));
//Connect to listening servers
ConnectionHub connectionHub = ConnectionHub.getInstance();
// A connection object represents a socket attached to an HL7 server
Connection connection = connectionHub.attach(serverIP, serverPort,
new PipeParser(), MinLowerLayerProtocol.class);
if (!connection.isOpen()) {
System.out.println("CONNNECTION is CLOSED");
connection = connectionHub.attach(serverIP, serverPort, new PipeParser(),
MinLowerLayerProtocol.class);
if (!connection.isOpen()) {
System.out.println("CONNNECTION is still CLOSED");
}
}
Initiator initiator = connection.getInitiator();
Message response = initiator.sendAndReceive(hl7msg);
String responseString = parser.encode(response);
System.out.println("Received response:\n" + responseString);
connection.close();
Result:
The first pass goes through perfectly, with request sent and ACK received. Any subsequent call to this method results in java.net.SocketException: Socket closed" on the client side.
If I remove the connection.close() call, then it will run fine for a certain amount of time then the socket will close itself.
If you are communicating via HL7 2.X, the expected behavior on the socket is to never disconnect -- you allocate the connection and keep the socket active. Said another way, an HL7 application does not act like a web browser wherein it connects as needed and disconnects when done. Rather, both ends work to keep the socket continuously connected. Most applications will be annoyed if you disconnect. Further, most integration engines have alerts that will fire if you are disconnected for too long.
Once the socket is connected, you need to use the HL7 Minimum Lower Layer Protocol (MLLP or MLP) to communicate the HL7 2.X content. If you are sending data, you should wait for an HL7 Acknowledgment before you send the next message. If you are receiving data, you should generate the HL7 Ack.
References:
MLP - http://www.hl7standards.com/blog/2007/05/02/hl7-mlp-minimum-layer-protocol-defined
Acks - http://www.corepointhealth.com/resource-center/hl7-resources/hl7-acknowledgement