I have the read the netty proxy server example. However I would like to know how to implement a client to talk to the proxy. The solution I am implementing is a server and it needs to connect to a socket server whenever a client connect to the server.So each client connected to the server will be able to send/receive data from another server.
I need help to inplement such architecture with netty because the server side is built on netty.
It seems what you want to implement can be pretty much answered by the Netty proxy example
The code segment below shows how you can connect to the remote server once a new client channel is opened.
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
// Suspend incoming traffic until connected to the remote host.
final Channel inboundChannel = e.getChannel();
inboundChannel.setReadable(false);
// Start the connection attempt.
ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort));
outboundChannel = f.getChannel();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// Connection attempt succeeded:
// Begin to accept incoming traffic.
inboundChannel.setReadable(true);
} else {
// Close the connection if the connection attempt has failed.
inboundChannel.close();
}
}
});
}
Once connected to the remote server, whatever the client sends (via inbound channel) is forwarded to the remote server (outbound channel).
I suggest you to follow and implement the proxy example if you haven't done it so already.
Related
I have a project where I have to build a system where multiples server communicate between each other to respond to clients.
I can make the client communicate with the server but I'm having problems on making the servers start a connection between them.
In the code below you can see that I have a list with the ip's of all the server. For each ip the current server tries to connect with the other server. You can also see that the server wait's for connections, in these case, connections from the other servers.
#Override
public void run() {
// Trying to connect with server
for (String serverIp : servers) {
System.out.println("Trying to connect with " + serverIp);
try {
Socket clientSocket = new Socket(serverIp, this.port);
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
} catch (Exception e) {
System.out.println("Error");
}
System.out.println("Connected with " + serverIp);
}
// Receiving connections from other servers
// In these case we call client to the other server
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
this.clientPool.submit(new ClientThread(clientSocket, this.streamHandler));
}
// serverSocket.close();
} catch (IOException e) {
Configuration.printError("Error starting server", e);
}
}
The problem is that the server needs to try to connect with the other servers and wait for connections from the other servers. And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Any suggestions on how to implement this with sockets?
It seems like you try to do this in steps, first all servers try to connect to the others, but no server have started to accept connections yet. And after the clientSocket has connected to servers, you then start to accept connections. It sounds like this can lead to a deadlock.
You know that each server must accept connections from other servers. You also know that each server need to initiate connections to the other servers.
You must either accept connections and initiated connections in two different threads, or you should use an asynchronous/event driven model and manage an event loop.
And after receiving a new connection it needs to stop trying to connect to the correspondent server or if the server have success trying to connect with the other server, it needs to stop receiving new connections from that server.
Here you want to avoid a race. This is easiest to do if each server wait X time before trying to connect to the other servers. This X should be a random delay from startup. E.g. server A waits 5 seconds before connecting, server B waits 1 second, and server C waits 13 seconds before connecting. But server B and C will not initiated any connections since server A already have established connections to those servers.
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 writing a game server in Java, and I'm using Netty 3.6.2. The game servers should accept no HTTP requests, as they simply handle game client data (which is purely bytes over TCP). When I load http://server-ip:game-servers-port in Chrome, I download a file with the game's handshake packet (which should not happen).
I bind to the game server's port like so:
ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
clientAcceptor = new ServerBootstrap(factory);
clientAcceptor.setOption("child.tcpNoDelay", true);
clientAcceptor.setOption("child.keepAlive", false);
clientAcceptor.setPipelineFactory(() -> Channels.pipeline(new PacketDecoder(), new ClientHandler()));
clientAcceptor.bind(new InetSocketAddress(Configurations.CHANNEL_GAME_PORT));
And I process requests in a SimpleChannelHandler, like so
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
// Encryption key code.
Packets.sendHello(ctx.getChannel(), ivRecv, ivSend);
ctx.getChannel().setAttachment(client);
}
How can I go about deciphering if an incoming request is using the HTTP protocol?
Edit: I should also say, it should also block any FTP, WebSocket, etc. protocol (essentially anything that isn't the game's protocol) on channel connect.
You can't expect to be able to disable HTTP requests if the first thing you do with an accepted connection is to send something.
Have the client do the first send in the handshake. Have the server start by doing a receive, and if it isn't the correct initial handshake packet, close the connection.
I'm using Netty for sending and receiving UDP Multicast messages and when I create multiple servers on same node it sometimes stops stop receiving packets from other servers. However even though they don't receive any packet from other servers, they still keep receiving packets that are sent using same multicast server.
Here is the server code:
multicastAddress = new InetSocketAddress("239.255.27.1", 14878);
Bootstrap a = new Bootstrap()
.group(group)
.channelFactory(() -> new NioDatagramChannel(InternetProtocolFamily.IPv4))
.localAddress(multicastAddress)
.option(ChannelOption.IP_MULTICAST_IF, NetUtil.LOOPBACK_IF)
.option(ChannelOption.SO_REUSEADDR, true)
.handler(new ChannelInitializer<NioDatagramChannel>() {
#Override
public void initChannel(NioDatagramChannel ch) throws Exception {
h.pipeline().addLast(new ChannelInboundHandler() {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg);
}
});
}
});
multicastServer = (NioDatagramChannel) a.bind().sync().channel();
multicastServer.joinGroup(multicastAddress, NetUtil.LOOPBACK_IF).sync();
The client periodically sends same ByteBuf:
multicastServer.writeAndFlush(new DatagramPacket(Unpooled.copyInt(1), multicastAddress));
When I start a server on a node, it starts receiving packets that are sent from that server. Then, if create the second server on the same node, it usually works and the server receives packets sent from both first and second server. However when I create a few more servers that are bound to same port (I use ChannelOption.SO_REUSEADDR so it should be a problem) sometimes all of the servers stop receiving packets from other servers instead only receive packets that are sent from the same server.
The problem is here:
.option(ChannelOption.IP_MULTICAST_IF, NetUtil.LOOPBACK_IF)
This tells UDP to only send membership reports to the localhost, so the other hosts don't know that this host is a member. Just remove it.
I would like to realize a proof of concept TCP transparent proxy in Vert.x.
Requirement
A verticle that listens on port X and when somebody connects and sends data it opens a client connection towards a preconfigured TCP server.
From this moment until any of the peers closes the connection, a bidirectional channel is kept and data flows up and down the channel from client to server and viceversa.
Here's my attempt which is not working.
vertx.createNetServer().connectHandler(new Handler<NetSocket>() {
public void handle(final NetSocket socket) {
vertx.createNetClient().connect(6367, "localhost", new Handler<NetSocket>() {
#Override
public void handle(NetSocket cliSocket) {
Pump.createPump(socket, cliSocket);
Pump.createPump(cliSocket, socket);
}
});
}
}).listen(3000);
}
At least this is how I understood the meaning of the Pump class:
http://vertx.io/core_manual_java.html#pump
Where's my error?
I just was missing to start the pumps. Then it worked.
Pump.createPump(socket, cliSocket).start();
Pump.createPump(cliSocket, socket).start();