If I have created class like this,
public class UserManagement{
Socket clientSocket;
public UserManagement(Socket soc,String usrN){
clientSocket = soc;
}
}
The application needs to maintain multiple clients,
So Every time it accepts a connection with
ServerSocket ser = new ServerSocket(1234);
Socket soc = ser.accept();
Will an array of UserManagement class, handle the socket.
I mean will it be possible to create an array and access the sockets individually.
Is that possible? I am not asking for advice to develop multithreaded client handler instead I'm asking if it is possible or not.
If yes what are PreCautions I will need to take.
Related
I'm new at network programming and i have been searching for a solution to my problem here but couldn't find one. What I want is to have a server that can receive files from multiple sockets at the same time. When a server accepts new connection socket it wraps that socket with a ClientThread class. Here is the code:
public class Server extends Thread {
private ServerSocket server;
private Vector<ClientThread> clients;
#Override
public void run() {
listen();
}
private void listen() {
new Thread("Listening Thread") {
#Override
public void run() {
while (true) {
try {
Socket socket = server.accept();
ClientThread newClient = new ClientThread(socket);
newClient.start();
clients.addElement(newClient);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}.start();
}
ClientThread is a private class inside the Server class. It's always listening for an Object from ObjectInputStream, but also I want to be able to receive one big file after the object. And that is why I think i should use multithreading. Here is the code:
private class ClientThread extends Thread {
public Socket socket;
private boolean loggedIn;
private ObjectInputStream ois;
private BufferedInputStream bis;
public ClientThread(Socket socket) {
this.socket = socket;
loggedIn = true;
InputStream is = socket.getInputStream();
ois = new ObjectInputStream(is);
bis = new BufferedInputStream(is);
}
#Override
public void run() {
receive();
}
private void receive() {
while (loggedIn) {
try {
// this method blocks i guess
Object object = ois.readObject();
// after the object comes the large file
byte[] bytes = new byte[SOME_SIZE];
int bytesRead;
int totalRead = 0;
// reading the large file into memory
while ((bytesRead = bis.read(bytes, totalRead, bytes.length - totalRead)) > -1) {
totalRead += bytesRead;
}
// rest of the code for handling received bytes.......
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}
}
}
I'm not sure if receiving data like this is even possible since all these client sockets are sending data to the same port on this server (i guess?). And if clients are sending data at the same time, Server needs to know which data is for which client. Is this already taken care of, or i need entirely different approach here?
I don't know if this is a stupid question, but like I said I'm just starting learning this stuff. Also i couldn't test my program because i don't even have code for the Client yet. Just want to make sure I don't go wrong at the very start. If this is wrong, feel free to post some ideas. :) Thanks!
For a start it's not bad :)
You can improve later on by using a Selector but that's another topic.
Some clarifications though: the ServerSocket listens on a specific port. When a remote client connects to it, a communication channel (i.e. socket) is created. If another client connects, another socket is created. Both sockets are different channels and won't interfere with each other because they are connected to a different remote IP and port.
It all has to do with how TCP headers and IP headers are formed: a TCP data packet is sent with its header containing the source and destination port, on top of IP header containing the source and destination IP. Those are used to discriminate between the different sockets.
Regarding the "broadcast" you want to do (as per your comment in #Rajesh's answer), you have options:
Do it yourself in pure TCP with ServerSocket and Socket like you started
Switch to UDP and use MulticastSocket, which has the advantage of issueing a single send, but you'll have to deal with missing/unordered datagrams in your client code (UDP does not guarantee delivery or ordering, like TCP does)
Check NIO with Selector and SocketChannel
Investigate frameworks like jGroups or Netty which do the I/O stuff for you
As you're learning, I suggest you do that in the above order. Using a framework is nice, but going through coding yourself will teach you a lot more.
This will work functionally. Each thread is reading from a separate socket connected to different client (address + port). They are separate streams, so no issues in reading from that like this.
However it would be much better to use asynchronous sockets.
Few things that can be taken care in the current implementation:
1) As a good practice, close the streams/sockets when transfer is complete.
2) For every new connection, a new thread is created. That will not scale. Even some one can send many requests and bring down your app. Would be better to use a thread pool. "ClientThread" can just implement "Runnable" and when a new connection is received, just submit the new "ClientThread" to thread pool. (In this case, would be better to name it as ClientTask instead of ClientThread)
As mentioned, it would be much more efficient and scalable to use asynchronous socket, but it will take some time master it. With this, you can use just one thread to read all sockets in parallel and depending on load, can use the same thread or a pool of threads to process the data received from all the sockets. Note that, even if use a pool, you will not need separate thread for processing each socket...Just to make best use of multiple CPU Cores, can use multiple threads to process the data.
You may try either java nio (Selector + SocketChannels) or netty library. Netty is much easier to use compared to nio.
The basic idea is that when the app starts a class will simply establish a socket connection to server and define output and input streams, those which should be accessed through all different activities that requires interaction so the socket must be always alive and ready.
My thoughts so far is to create a class that will simply create socket and connections:
public class connection {
private String HostIPaddress = "XXX.XXX.XXX.XXX";
private int PORT = XXXX;
public Socket sock = null;
public DataOutputStream out = null;
public DataInputStream in = null;
public void assignStreams(){
try{
sock = new Socket(getHostIPaddress(),getPORT());
out = new DataOutputStream(sock.getOutputStream());
in = new DataInputStream(sock.getInputStream());
}catch (Exception ex) {
Log.i("Connection Error",ex.toString());
}
}
}
and then from the activity that run first, create a static object of this class and all other activities can access this object.. It sounds that this would work but I was wishing for some more thoughts or feedback?
No, not a good idea. The user can switch off internet at any point in time and your class is using a network connection when one may not be needed at all. Cleaning up after the socket is also impossible. How do you know when to close() it ?
You are just better off creating these as needed. Your class also has poor encapsulation.
public Socket sock = null;
public DataOutputStream out = null;
public DataInputStream in = null;
These streams can be reassigned at any time. Protect them with getters() and setters().
I wouldn't know why it's not possible.
Wether it's a good idea or not, I don't know.
My two cents to achieve it your way is, create a singleton class.
singleton pattern example
Credits for the article go to http://www.javacoffeebreak.com/
Aside from their barebone implementation, make sure you have a method to retrieve your socket and just as important, close your socket. Which you can do when your app gets destroyed. I believe the application object's onDestroy method is a decent place to do this as from what I remember that will be the last onDestroy method called before your application is taken completely out of memory.
Having that said.. what if your application crashes? you will need to clean up somehow.
Creating a socket on demand will probably be the safest way.
Note that, if you have a socket that is always open throughout activities it is easy to forget that you need to close it. Another reason to manage the socket per activity instead of globally.
In my Java Sockets program, I have implemented a client-server Observer pattern. That is, the server subject publishes its server events to client observers that have subscribed to the server. That's the theory.
In practice, I am unable to send the client observer through the socket to subscribe to the server. The error that comes up is: "java.io.NotSerializableException: java.net.Socket." I think this means Java is complaining that the client observer contains a Socket which, as we all know, is not Serializable.
However, the Socket is the means of communication between the client and the server!
How can I implement a client-server Observer pattern when the client appears to contain a non-Serializable roadblock?
Here is a code overview to give you an understanding of what is happening:
Server
public class Server implements ServerSocketPublisher {
// traditional Observer publisher methods implemented here, such as register,
// deregister, notifySubscribers
// ServerSocket implemented here. Waiting on accept()
}
Client
public class Client implements ClientSocketSubscriber, Serializable {
// traditional Observer subscriber methods implemented here, i.e. updateClient
Socket connectingSocket = null; //I SUSPECT THIS VARIABLE IS THE PROBLEM
try {
connectingSocket = new Socket();
// set SocketAddress and timeout
connectingSocket.connect(sockAddr, timeout)
if (connectingSocket.isConnected()) {
ObjectOutputStream oos = new ObjectOutputStream
(connectingSocket.getOutputStream());
oos.writeObject(this); // THIS LINE THROWS THE ERROR in STACKTRACES
oos.flush();
oos.close();
}
} catch (/*various exceptions*/) {
}
// close connectingSocket
}
You have couple of ways to get this fixed:
Mark your socket as transient
transient Socket connectingSocket = null;
Instead of implementing Serializable implement Externalizable and then in your implementation of read and write object ignore the Socket.
Along with this you should also read
About transient:
Post on SO
About Externalizable :
Javabeat
you cannot write the Client to the output stream socket since it contains a Socket. If you serialize the Client, you serialize all non-transient vars in it, and thats when you get the exception.
However, the server already has the socket on its side, so you don't need to send it and the client across. If all clients are observers once the connection has occurred you can pretty much at that point start waiting for data from the socket on the client side. The server will need to keep a list of sockets its ready to broadcast to, and when it gets an event to send, loop over all sockets and send the register, deregister, notifySubscriber messages
Alternatively if you wish to treat the client as an object on the server side and call methods on it (which it looks like you might be trying to do), maybe you need to look into RMI - where the server holds stubs of the client and invoking the stub sends messages to the client.
I have a questions that is perhaps indicative of my lack in experience and the fact that I am still a student.
I established a socket connection client side(server is already running) and after making the connection on the client side I immediately go to a different Form(that is also based on the client side) where I want to verify userName and password against database on the server side. Problem is, I feel that I do not want to make the connection again as I have already done this on the previous Form
clientSocket = new Socket(hostAdress, 7777);
How can I 'carry over' the fact that I have a connection already to the new form so that I just create and input and output stream without making the connection again on the new form.
Sorry, hope this question makes sense
Kind regards
Arian
Create a method like this:
public Socket getSocket() {
return clientSocket;
}
and call it from the other class (assuming that you have a reference to that object.
or static variable:
private static Socket clientSocket = new Socket(hostAdress, 7777);
and as Binyamin wrote, create a method , but in this case it would be static method
I have this code:
ServerSocket serverSideSocket = new ServerSocket(1234);
serverSideSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(serverSideSocket.getInputStream()));
And compiler writes me that it cannot find "getInputStream". I do not understand why. In the beginning of my code I do import java.net.*.
Calling of accept returns instance of Socket which has required method getInputStream.
The code might look like this:
ServerSocket serverSideSocket = new ServerSocket(1234);
Socket socket = serverSideSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Great tutorial how to work with sockets in java: http://java.sun.com/docs/books/tutorial/networking/sockets/index.html
This because conceptually a ServerSocket doesn't provide a direct connection object that can be used to send and receive data. A ServerSocket is a tool that you can use with the .accept() method to let it listen on the choosen port and generate a new real connection when a client tries to connect.
That's why you can't get an InputStream from a ServerSocket. Since many clients can connect to the same server, every client will make the server socket generate a new Socket (that is an opened TCP connection) that is returned from .accept() through which you can send and receive using its InputStream and OutputStream.