Framing doesn't appear to be working... When two clients connect at the same time I get the same data from both when it should be different.
When a client's channel becomes active it sends a HandshakeRequest which is pretty much just a string with the servers hostname to allow the server to fetch some details about it from the database.
#Override
public void channelActive(ChannelHandlerContext context) {
HandshakeRequest packet = new HandshakeRequest();
packet.setHostname(Client.HOSTNAME);
context.writeAndFlush(packet);
}
HandshakeRequest:
#Getter #Setter private String hostname;
public HandshakeRequest() {
super(Packet.HANDSHAKE_REQUEST);
}
#Override
public void write(ByteBuf buf) {
writeString(hostname, buf);
}
#Override
public void read(ByteBuf buf) {
hostname = readString(buf);
}
Initializer:
#Override
public void initChannel(SocketChannel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new PacketEncoder());
pipeline.addLast(new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, 0, 2, 0, 2));
pipeline.addLast(new PacketDecoder());
pipeline.addLast(new ClientHandler(client));
}
PacketEncoder:
#Override
protected void encode(ChannelHandlerContext context, DefinedPacket packet, ByteBuf buf) {
buf.writeInt(packet.packet().getId());
packet.write(buf);
}
PacketDecoder:
#Override
protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) {
int id = in.readInt();
DefinedPacket packet = Packet.getTypeById(id).getPacket();
if(packet != null) {
packet.read(in);
packet.setId(id);
out.add(packet);
} else {
in.skipBytes(in.readableBytes());
}
}
DefinedPacket (This is an abstract class extended by all packets):
public static void writeString(String s, ByteBuf buf) {
if(s.length() > Short.MAX_VALUE) {
throw new OverflowPacketException(String.format("Cannot send string longer than Short.MAX_VALUE (got %s characters)", s.length()));
}
byte[] b = s.getBytes(Charsets.UTF_8);
writeVarInt(b.length, buf);
buf.writeBytes(b);
}
public static String readString(ByteBuf buf) {
int len = readVarInt(buf);
if(len > Short.MAX_VALUE) {
throw new OverflowPacketException(String.format("Cannot receive string longer than Short.MAX_VALUE (got %s characters)", len));
}
byte[] b = new byte[len];
buf.readBytes(b);
return new String(b, Charsets.UTF_8);
}
public static int readVarInt(ByteBuf input) {
return readVarInt(input, 5);
}
public static int readVarInt(ByteBuf input, int maxBytes) {
int out = 0;
int bytes = 0;
byte in;
while(true) {
in = input.readByte();
out |= (in & 0x7F) << (bytes++ * 7);
if(bytes > maxBytes) {
throw new RuntimeException("VarInt too big");
}
if((in & 0x80) != 0x80) {
break;
}
}
return out;
}
public static void writeVarInt(int value, ByteBuf output) {
int part;
while(true) {
part = value & 0x7F;
value >>>= 7;
if(value != 0) {
part |= 0x80;
}
output.writeByte(part);
if(value == 0) {
break;
}
}
}
private final Packet type;
#Getter #Setter private int id;
public DefinedPacket(Packet type) {
this.type = type;
}
public Packet packet() {
return type;
}
public abstract void write(ByteBuf buf);
public abstract void read(ByteBuf buf);
Could you provide full class for
#Override
public void initChannel(SocketChannel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new PacketEncoder());
pipeline.addLast(new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, 0, 2, 0, 2));
pipeline.addLast(new PacketDecoder());
pipeline.addLast(new ClientHandler(client));
}
??
Where are you getting client from for passing it to ClientHandler's constructor?
I've solved the problem. It turned out to be an issue with the way new instances of packets were being handled after they'd been decoded (was reusing the same object for each instance of the same packet).It was just a really silly mistake :P
Related
I wrote a program in Java which call OpenMPI in single thread for communication. Isend/recv is used to prevent deadlock. The caller invoke send method and then, all send request put in queue. The network thread get request from queue to sent.
class NetworkThread extends Thread {
private final ConcurrentLinkedQueue<SendRequest> sendQueue = new ConcurrentLinkedQueue<>();
private final List<Request> activeSends = new LinkedList<>();
private final List<RecvRequest> recvList = new LinkedList<>();
private volatile boolean shutdown;
#Override
public void run() {
System.out.println("network thread started");
try {
loop();
} catch (MPIException e) {
e.printStackTrace();
}
}
void loop() throws MPIException {
while (!shutdown) {
Status status = MPI.COMM_WORLD.iProbe(MPI.ANY_SOURCE, MPI.ANY_TAG);
if (status != null) {
int source = status.getSource();
int tag = status.getTag();
int sizeInBytes = status.getCount(MPI.BYTE);
ByteBuffer buffer = MPI.newByteBuffer(sizeInBytes);
MPI.COMM_WORLD.recv(buffer, sizeInBytes, MPI.BYTE, source, tag);
byte[] data = new byte[sizeInBytes];
buffer.get(data);
RecvRequest recvRequest = new RecvRequest(data, source, tag);
synchronized (recvList) {
recvList.add(recvRequest);
}
}
SendRequest sendRequest;
while ((sendRequest = sendQueue.poll()) != null) {
byte[] data = sendRequest.getData();
ByteBuffer buffer = MPI.newByteBuffer(data.length);
buffer.put(data);
Request request = MPI.COMM_WORLD.iSend(buffer, data.length, MPI.BYTE, sendRequest.getDest(), sendRequest.getTag());
synchronized (activeSends) {
activeSends.add(request);
}
}
//delete sent record
synchronized (activeSends) {
Iterator<Request> iterator = activeSends.iterator();
while (iterator.hasNext()) {
Request request = iterator.next();
if (request.test())
iterator.remove();
}
}
}
}
public void send(byte[] data, int dest, int tag) {
SendRequest sendRequest = new SendRequest(data, dest, tag);
sendQueue.add(sendRequest);
}
public byte[] read(int source, int tag) {
byte[] data;
while ((data = tryRead(source, tag)) == null) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return data;
}
public byte[] tryRead(int source, int tag) {
byte[] data = null;
synchronized (recvList) {
Iterator<RecvRequest> iterator = recvList.iterator();
while (iterator.hasNext()) {
RecvRequest recvRequest = iterator.next();
if (recvRequest.getSource() == source && recvRequest.getTag() == tag) {
iterator.remove();
data = recvRequest.getData();
break;//just get one
}
}
}
return data;
}
public void shutdown() {
shutdown = true;
//waiting for all sent
synchronized (activeSends) {
while (activeSends.size() > 0)
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SendRequest {
private byte[] data;
private int dest;
private int tag;
SendRequest(byte[] data, int dest, int tag) {
this.data = data;
this.dest = dest;
this.tag = tag;
}
public int getTag() {
return tag;
}
public int getDest() {
return dest;
}
public byte[] getData() {
return data;
}
}
class RecvRequest {
private byte[] data;
private int source;
private int tag;
RecvRequest(byte[] data, int source, int tag) {
this.data = data;
this.source = source;
this.tag = tag;
}
public int getTag() {
return tag;
}
public int getSource() {
return source;
}
public byte[] getData() {
return data;
}
}
I also wrote a test case which implemented broadcast data to every process for five times in random time interval (except myself and master). Hopefully, all process will finish the send/receive task then exit.
public class BroadcastTest {
private static final int TAG_MPI = 123;
static int rank;
static String host;
static {
try {
host = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws MPIException, InterruptedException, UnknownHostException {
MPI.Init(args);
int rank = MPI.COMM_WORLD.getRank();
int size = MPI.COMM_WORLD.getSize();
BroadcastTest.rank = rank;
if (rank == 0) {
System.out.println(String.format("total %d machines", size));
System.out.println("master started");
} else {
NetworkThread networkThread = new NetworkThread();
networkThread.start();
Thread sendTh = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep((long) (Math.random() * 1000)); //send data five times in random interval
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int machineId = 1/* skip master */; machineId < size; machineId++) {
if (machineId == rank) continue;//skip myself
networkThread.send(new byte[4096], machineId, TAG_MPI); //send 4K bytes data
}
}
});
//receive data
Thread recvTh = new Thread(() -> {
for (int i = 0; i < 5; i++) {
for (int machineId = 1; machineId < size; machineId++) {
if (machineId == rank) continue;
byte[] bytes = networkThread.read(machineId, TAG_MPI);
}
}
});
sendTh.start();
recvTh.start();
sendTh.join();
recvTh.join();
networkThread.shutdown();
networkThread.join();
}
System.out.println(String.format("%s exit", host));
MPI.Finalize();
}
}
COMMAND LINE:
/home/gongsf/openmpi-2.1.2/bin/mpirun --prefix /home/gongsf/openmpi-2.1.2 -bycore -nooversubscribe -machinefile /home/gongsf/JavaMPI/myhosts /home/gongsf/jdk1.8.0_144/bin/java -classpath /home/gongsf/JavaMPI/lib/*:/home/gongsf/JavaMPI/out/production/JavaMPI BroadcastTest
QUESTION: This program works fine at lower processes e.g. slots=4. But when increase the slots or data size to send, the program enter deadlock state occasionally. I tried to alter the OpenMPI version (3.0, 2.1.2, 1.7.5), but seems doesn't work.
i try to send the POJO "SecureMessageServerClientMessage" over network to an client. Both are created with the netty-Framework for Async. Socket communications. I am really new to netty, so i take on of the Example code and want to change it, so that it send my POJO over network. I know that is a lot of code but its nearly the sample of them but it dont work .. It would be really nice if some one could tell my why it does not work ..
Here are my classes: Server Main:
public final class SecureChatServer {
static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
public static void main(String[] args) throws Exception {
SelfSignedCertificate ssc = new SelfSignedCertificate();
SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new SecureChatServerInitializer(sslCtx));
b.bind(PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
SecureChatServerHandler:
public class SecureChatServerHandler extends SimpleChannelInboundHandler<SecureMessageServerClientMessage> {
static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
private ArrayList<SecureMessageServerUser> userList = new ArrayList();
#Override
public void channelActive(final ChannelHandlerContext ctx) {
// Once session is secured, send a greeting and register the channel to the global channel
// list so the channel received the messages from others.
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
new GenericFutureListener<Future<Channel>>() {
#Override
public void operationComplete(Future<Channel> future) throws Exception {
channels.add(ctx.channel());
}
});
}
#Override
public void channelRead0(ChannelHandlerContext ctx, SecureMessageServerClientMessage msg ) throws Exception {
System.out.println("Nachricht empfangen!");
System.out.println("Typ: "+msg.getType());
//Send the received message to all channels but the current one.
for (Channel c: channels) {
if (c != ctx.channel()) {
c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
} else {
c.writeAndFlush("[you] " + msg + '\n');
}
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
Initializer (Server):
public class SecureChatServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public SecureChatServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// Add SSL handler first to encrypt and decrypt everything.
// In this example, we use a bogus certificate in the server side
// and accept any invalid certificates in the client side.
// You will need something more complicated to identify both
// and server in the real world.
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
// On top of the SSL handler, add the text line codec.
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEncoder());
// and then business logic.
pipeline.addLast(new SecureChatServerHandler());
}
}
Here is the code of my client:
public final class SecureChatClient {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).handler(new SecureChatClientInitializer(sslCtx));
// Start the connection attempt.
Channel ch = b.connect(HOST, PORT).sync().channel();
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
if("send".equals(line)){
System.out.println("Test");
lastWriteFuture = ch.writeAndFlush(new SecureMessageServerClientMessage(1, "test"));
if(lastWriteFuture.isSuccess()){
System.out.println("Success");
}
}
// Sends the received line to the server.
//lastWriteFuture = ch.writeAndFlush(line + "\r\n");
// If user typed the 'bye' command, wait until the server closes
// the connection.
if ("bye".equals(line.toLowerCase())) {
ch.closeFuture().sync();
break;
}
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
} finally {
// The connection is closed automatically on shutdown.
group.shutdownGracefully();
}
}
}
And here the handler:
public class SecureChatClientHandler extends SimpleChannelInboundHandler<SecureMessageServerClientMessage> {
#Override
public void channelRead0(ChannelHandlerContext ctx, SecureMessageServerClientMessage msg) throws Exception {
System.err.println(msg);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
And at last my POJO:
public class SecureMessageServerClientMessage implements Serializable{
private String message;
private int type;
static final int LISTUSER = 0, MESSAGE = 1, LOGOUT = 2, LOGIN = 3;
private String sender;
private String empfaenger;
private ArrayList<SecureMessageServerUser> userList = new ArrayList();
//Erste MSG, Login am Server
public SecureMessageServerClientMessage(int type, String sender){
this.type=type;
this.sender=sender;
}
//Nur für den Clienten, als Anfrage für die user-List
public SecureMessageServerClientMessage(int type){
this.type=type;
}
//Für MessageTyp 0 - LISTUSER, es wird nur die aktuelle User-Liste übertragen
public SecureMessageServerClientMessage(int type, ArrayList userList){
this.userList=userList;
}
//Für MessageTyp 1 - MESSAGE Es wird der Empfänger, und die Nachricht übertragen
public SecureMessageServerClientMessage(int type, String message, String empfaenger, String sender){
this.type=type;
this.message=message;
this.sender=sender;
this.empfaenger=empfaenger;
}
//Für MessageTyp 1 - Msg, die weitergeleitet werden
public SecureMessageServerClientMessage(int type, String message, String sender){
this.type=type;
this.message=message;
this.sender=sender;
}
public String getMessage(){
return this.message;
}
public int getType(){
return type;
}
public String getSender(){
return this.sender;
}
public ArrayList getList() {
return userList;
}
public ArrayList getUserList() {
return userList;
}
public String getEmpfaenger(){
return this.empfaenger;
}
}
I have an sync Client, how to make this async Client? Client connects properly then it writes to channel, and then it waits (no keys ready because there is nothing to read from channel), now I want it to start writing to channel again, how to achieve this ? Thanks
public class Client {
static class SocketTest implements Runnable {
private Selector selector;
private int sessionID = 0;
int port;
String address;
private List<Message> dummyTypeOneResults = new LinkedList<Message>();
private List<Message> dummyTypeTwoResults = new LinkedList<Message>();
public SocketTest(String address, int port){
this.port = port;
this.address = address;
}
#Override
public void run() {
SocketChannel channel;
try {
selector = Selector.open();
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_CONNECT);
channel.connect(new InetSocketAddress(this.address,this.port));
while (!Thread.interrupted()){
selector.selectNow();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()){
SelectionKey key = keys.next();
keys.remove();
if (!key.isValid()) continue;
if (key.isConnectable()){
connect(key);
}
if (key.isWritable()){
if(sessionID > 200000){
//force disconnect
System.out.println("sessionID reached limit forcing disconnet");
key.cancel();
//call calculate
calculate();
close();
return;
} else {
write(key);
}
}
if (key.isReadable()){
read(key);
}
}
}
} catch (IOException e1) {
e1.printStackTrace();
} finally {
close();
}
}
private void calculate() throws IOException{
//open file
File file = new File("results_nio.txt");
// if file doesnt exists, then create it
FileWriter fw = null;
fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
long totalDifferenceSum = 0;
long messageCount = 0;
for (Message message : dummyTypeOneResults) {
long diff = message.getProcessed() - message.getDispatched();
String out = "message with ID: "+message.getSessionID()+" Trip time in seconds %f %n ";
System.out.format(out,diff/1000000000.0);
bw.write(String.format(out,diff/1000000000.0));
totalDifferenceSum +=diff;
messageCount++;
}
for (Message message : dummyTypeTwoResults) {
long diff = message.getProcessed() - message.getDispatched();
String out = "message with ID: "+message.getSessionID()+" Trip time in seconds %f %n ";
System.out.format(out,diff/1000000000.0);
bw.write(String.format(out,diff/1000000000.0));
totalDifferenceSum +=diff;
messageCount++;
}
String totalString = "Total round trip time in seconds %f %n ";
System.out.format(totalString,totalDifferenceSum/1000000000.0);
bw.write(String.format(totalString,totalDifferenceSum/1000000000.0));
double average = messageCount > 0 ? (double)totalDifferenceSum/messageCount : 0;
String averageString = "Average trip time in seconds %f %n ";
System.out.format(averageString,average/1000000000.0);
bw.write(String.format(averageString,average/1000000000.0));
bw.close();
}
private void close(){
try {
selector.close();
} catch (IOException e) {
System.err.println(e);
}
}
private void read(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int length;
try {
length = channel.read(readBuffer);
System.out.println("Bytes read from server: "+length);
if(length != -1){
byte[] bytes;
readBuffer.flip();
bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes, 0, bytes.length);
//create Message
ByteBuffer prepareBuffer = ByteBuffer.wrap(bytes);
int type = prepareBuffer.getInt();
int sessionID = prepareBuffer.getInt();
long dispatched = prepareBuffer.getLong();
Message message = new Message(sessionID, type, dispatched, bytes);
message.setProcessed(System.nanoTime());
if(type == Message.DUMMY_ONE){
dummyTypeOneResults.add(message);
} else if (type == Message.DUMMY_TWO) {
dummyTypeTwoResults.add(message);
}
}
} catch (IOException e) {
System.out.println("Reading problem, closing connection");
key.cancel();
channel.close();
return;
}
if (length == -1) {
System.out.println("Nothing was read from server");
//channel.close();
key.cancel();
System.out.println("Send againg new message ");
key.interestOps(SelectionKey.OP_CONNECT);
return;
}
readBuffer.flip();
byte[] buff = new byte[1024];
readBuffer.get(buff, 0, length);
key.interestOps(SelectionKey.OP_WRITE);
readBuffer.clear();
}
private void write(SelectionKey key) throws IOException {
//Message format |typeID|sessionID|startTime
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer message = ByteBuffer.allocate(16);
if(sessionID % 2 == 0){
message.putInt(Message.DUMMY_ONE);
} else {
message.putInt(Message.DUMMY_TWO);
}
message.putInt(sessionID);
message.putLong(System.nanoTime());
sessionID++;
message.flip();
int bytesWritten = channel.write(message);
System.out.println("client write(): bytesWritten :"+bytesWritten);
// lets get ready to read.
key.interestOps(SelectionKey.OP_READ);
}
private void connect(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if (channel.isConnectionPending()){
boolean finished = channel.finishConnect();
if (!finished) {
key.cancel();
}
}
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_WRITE); // \p was
// channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
public static void main(String[] args) {
int DEFAULT_PORT = 9090;
String IP = "127.0.0.1";
if(args.length > 1){
if(args[0]!=null){
IP=args[0];
}
if(args[1]!=null){
DEFAULT_PORT=Integer.valueOf(args[1]);
}
}
new Thread(new SocketTest(IP,DEFAULT_PORT)).start();
}
//and Message class
public class Message implements Serializable {
public static final int DUMMY_ONE = 1;
public static final int DUMMY_TWO = 2;
private static final long serialVersionUID = -555511105603152223L;
// could be message header
protected int sessionID;
protected int type;
protected long created = System.currentTimeMillis();
protected long dispatched;
protected long processed;
protected Object payload;
public Message(int sessionID, int type, long dispatched) {
super();
this.sessionID = sessionID;
this.type = type;
this.dispatched = dispatched;
}
public Message(int sessionID, int type, long dispatched, Object payload) {
super();
this.sessionID = sessionID;
this.type = type;
this.dispatched = dispatched;
this.payload = payload;
}
public int getSessionID() {
return sessionID;
}
public void setSessionID(int sessionID) {
this.sessionID = sessionID;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public long getCreated() {
return created;
}
public void setCreated(long created) {
this.created = created;
}
public long getDispatched() {
return dispatched;
}
public void setDispatched(long dispatched) {
this.dispatched = dispatched;
}
public long getProcessed() {
return processed;
}
public void setProcessed(long processed) {
this.processed = processed;
}
public Object getPayload() {
return payload;
}
public void setPayload(Object payload) {
this.payload = payload;
}
#Override
public String toString() {
return "Message [sessionID=" + sessionID + ", type=" + type
+ ", created=" + created + ", dispatched=" + dispatched + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (created ^ (created >>> 32));
result = prime * result + (int) (dispatched ^ (dispatched >>> 32));
result = prime * result + ((payload == null) ? 0 : payload.hashCode());
result = prime * result + (int) (processed ^ (processed >>> 32));
result = prime * result + sessionID;
result = prime * result + type;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Message other = (Message) obj;
if (created != other.created)
return false;
if (dispatched != other.dispatched)
return false;
if (payload == null) {
if (other.payload != null)
return false;
} else if (!payload.equals(other.payload))
return false;
if (processed != other.processed)
return false;
if (sessionID != other.sessionID)
return false;
if (type != other.type)
return false;
return true;
}
}
You are confused between 'asynchronous' and 'non-blocking'.
You are operating in non-blocking mode, but you're blocking in select(). This is normal.
If you want asynchronous I/O, you need to use an AsynchronousSocketChannel. It is a completely different programming paradigm.
I try to implement a SFTP upload with a progress bar.
Unfortunately the progress bar is not updated...
Here is a part of my code:
public class MainView extends JFrame implements SftpProgressMonitor {
private static final Logger LOG = Logger.getLogger(MainView.class);
private String _source;
private JProgressBar _progressBar;
private JButton _button;
public MainView() {
initComponents();
}
void initComponents() {
_button = new JButton("Send");
_button.addActionListener(new ActionListener() {
// If clicked, send event to controller...
});
_progressBar = new JProgressBar();
// Do init stuff here
// ...
}
#Override
public boolean count(long byteTransfered) {
int transfered = _progressBar.getValue();
transfered += byteTransfered;
_progressBar.setValue(transfered);
return true;
}
#Override
public void end() {
LOG.info("Transfer of "+_source+" finished!");
}
#Override
public void init(int op, String src, String dest, long max) {
_progressBar.setValue(0);
_progressBar.setMinimum(0);
_progressBar.setMaximum((int) max);
_source = src;
}
}
public class Controller {
private final MainView _view;
private final SftpClient _ftp;
private final Server _server;
public Controller() {
_server = new Server("192.168.0.1");
_view = new MainView();
_ftp = new SftpClient(_server);
_view.setVisible(true);
}
public void send() {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
public void run() {
File testFile = new File("/PathToFile/file.txt");
String remoteDir = "/MyRemoteDir/";
_ftp.put(testFile, remoteDir, testFile.getName(), _view);
}
});
}
public static void main(String[] args) {
Controller controller = new Controller();
}
}
public class SftpClient {
private static final Logger LOG = Logger.getLogger(SftpClient.class);
/** Connection port number */
public static final int PORT = 22;
/** SECURED protocol name */
public static final String PROTOCOL = "sftp";
/** Connection time out in milliseconds */
public static final int TIME_OUT = 3000;
private Server _server;
/** This class serves as a central configuration point, and as a factory for Session objects configured with these settings */
private JSch _client;
/** A session represents a connection to a SSH server */
private Session _session;
/** Channel connected to a SECURED server (as a subsystem of the SSH server) */
private ChannelSftp _channelSftp;
/**
* Value returned by the last executed command.
*/
private int _exitValue;
public SftpClient(Server server) {
_client = new JSch();
_server = server;
}
protected void connect() throws AuthenticationException, Exception {
try {
if (_client == null) {
_client = new JSch();
}
if (_session == null) {
_session = _client.getSession(_server.getLogin(), _server.getAddress(), PORT);
_session.setConfig("StrictHostKeyChecking", "no");
_session.setPassword(_server.getPassword());
if (LOG.isDebugEnabled()) {
LOG.debug("Connecting to "+_server.getAddress()+" with login "+_server.getLogin()+"...");
}
}
if (!_session.isConnected()) {
_session.connect(TIME_OUT);
}
if(_channelSftp == null || _channelSftp.isConnected() == false) {
Channel c = _session.openChannel(PROTOCOL);
c.connect();
// disconnect previous channel if it has not been killed properly
if (_channelSftp != null && _channelSftp.isConnected()) {
_channelSftp.disconnect();
}
_channelSftp = (ChannelSftp) c;
}
if (LOG.isInfoEnabled()) {
LOG.info("Connected to "+_server.getAddress()+" with login "+_server.getLogin());
}
} catch(JSchException e) {
if ("Auth fail".equals(e.getMessage())) {
throw new AuthenticationException(e);
} else {
throw new Exception(e);
}
}
}
protected void connect(String path) throws AuthenticationException, Exception {
connect();
if (_channelSftp != null && _channelSftp.isConnected()) {
_channelSftp.cd(path);
}
}
#Override
public void disconnect() {
if (_channelSftp != null && _channelSftp.isConnected()) {
_channelSftp.disconnect();
_channelSftp.exit();
}
if (_session != null && _session.isConnected()) {
_session.disconnect();
if (LOG.isInfoEnabled()) {
LOG.info("SECURED FTP disconnected");
}
}
}
#Override
public void put(File localFile, String destPath, SftpProgressMonitor monitor) throws Exception {
put(localFile, destPath, localFile.getName(), monitor);
}
#Override
public void put(File localFile, String destPath, String remoteFileName, SftpProgressMonitor monitor) throws Exception {
if (LOG.isInfoEnabled()) {
LOG.info("Send file "+localFile+" to "+_server+" in "+destPath);
}
if (localFile == null) {
_exitValue = -1;
LOG.error("The given local file is null. Aborting tranfer.");
return;
}
if (!localFile.exists()) {
_exitValue = -1;
LOG.error("'"+localFile+"' doesn't exist. Aborting tranfer.");
return;
}
if(!localFile.canRead()) {
_exitValue = -1;
LOG.error("Cannot read '"+localFile+"'. Aborting tranfer.");
return;
}
final InputStream input = new BufferedInputStream(new FileInputStream(localFile));
if (input == null || input.available() <= 0) {
_exitValue = -1;
LOG.error("Cannot read file "+localFile);
return;
}
try {
connect(destPath);
_channelSftp.put(input, remoteFileName, monitor);
_exitValue = _channelSftp.getExitStatus();
} catch(SftpException e){
throw new IOException(e);
} finally {
if (_channelSftp != null && _channelSftp.isConnected()) {
_channelSftp.disconnect();
_channelSftp.exit();
}
IOUtils.closeQuietly(input);
}
}
}
The count() method is never called. And the source and destination strings of the init contain both -. Am I doing it wrong?
I've changed my code and it works now. I don't use put(InputStream src, String dst, int mode) anymore but put(String src, String dst, SftpProgressMonitor monitor).
I've also implemented a DefaultBoundedRangeModel class. It modifies directly the JProgressBar and it is more interesting for me because I have several files to transfer.
public class ProgressModel extends DefaultBoundedRangeModel implements SftpProgressMonitor {
/** Logger */
private static Logger LOG = Logger.getLogger(ProgressModel.class);
private String _fileBeingTransfered;
/**
* Constructs the model.
*/
public ProgressModel() {
_fileBeingTransfered = "";
}
#Override
public boolean count(long count) {
int value = (int) (getValue() + count);
setValue(value);
fireStateChanged();
if(value < getMaximum()) {
return true;
} else {
return false;
}
}
#Override
public void end() {
LOG.info(_fileBeingTransfered+" transfert finished.");
if(getValue() == getMaximum()) {
LOG.info("All transfers are finished!");
}
}
#Override
public void init(int op, String src, String dest, long max) {
LOG.info("Transfering "+src+" to "+dest+" | size: "+max);
_fileBeingTransfered = src;
}
}
I don't know what caused my problem. Maybe it was the put method.
In order to get updates you have to send reference to monitor to FTP client. And you do this:
_ftp.put(testFile, remoteDir, testFile.getName(), _view);
However what _view is? It is a private final field of class Controller that is never initialized. Therefore it is null. You implemented your callback method count() into class MainView but do not send reference to it to the FTP client. I do not know where do you create instance of Controller but you should pass reference to instance of MainView to it.
public class ServerPipelineFactory implements ChannelPipelineFactory {
#Override
public ChannelPipeline getPipeline() throws Exception {
PacketFrameDecoder decoder = new PacketFrameDecoder();
PacketFrameEncoder encoder = new PacketFrameEncoder();
return Channels.pipeline(decoder, encoder, new Handler());
}
}
and my decoder
public class PacketFrameDecoder extends
ReplayingDecoder<PacketFrameDecoder.DecoderState> {
public enum DecoderState {
READ_CONTENT;
}
private int length;
public PacketFrameDecoder() {
super(DecoderState.READ_CONTENT);
}
#Override
protected Object decode(ChannelHandlerContext chc, Channel chnl,
ChannelBuffer cb, DecoderState state) throws Exception {
switch (state) {
case READ_CONTENT:
for (int i = 0; i < cb.capacity(); i ++) {
byte b = cb.getByte(i);
System.out.println((char) b);
}
return null;
default:
throw new Error("Shouldn't reach here.");
}
}
}
and I send messages
Socket fromserver = new Socket("localhost", 7283);
PrintWriter out = new PrintWriter(fromserver.getOutputStream(), true);
int data = 12;
out.write(data);
out.flush();
out.close();
fromserver.close();
but when I get bytes- I have cb.capacity() = 256
and message "?0?0" System.out.println((char) b);
please help
Using capacity is wrong a it is the "max" amount of bytes in the buffer. Also starting at position 0 is wrong as the readerIndex could be on an other position. Please read the apidocs of ChannelBuffer which all of this explains in great detail.