I am trying to create a chat application which has one publisher, one server and multiple subscribers. The publisher(Sending to port 8000) sends a message to the server(listening on port 8000 and 5000) and which forwards it further to the subscriber(listening on port 5000).
Now so far I can create multiple publishers and the communication between server and publisher is working, however, I am not able to send it to the subscriber the message sent by the publisher
Server Side Code
package serverclient;
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server extends Thread{
private Socket socket;
private int clientNumber;
public Server(Socket socket, int clientNumber){
this.socket = socket;
this.clientNumber = clientNumber;
if(socket.getLocalPort() == 5000)System.out.print("\nSubscriber "+ clientNumber +" is connected to the server");
if(socket.getLocalPort() == 8000)System.out.print("\nPublisher "+ clientNumber +" is connected to the server");
}
#Override
public void run(){
try {
BufferedReader dStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while(true){
synchronized(this){
String clMessage = dStream.readLine();
System.out.println("\n"+clMessage);
// if(socket.getLocalPort() == 5000){
out.println("Hey the server is sending the message to subscriber");
// }
//out.println("Hey the publisher has sent the message : " + clMessage);
}
}
} catch (IOException ex) {
System.out.print("\nError has been handled 1\n");
}finally{
try {
socket.close();
} catch (IOException ex) {
System.out.print("\nError has been handled 2\n");
}
}
}
public static void main(String [] args) throws IOException{
int subNumber = 0;
int pubNumber = 0;
ServerSocket servSockpub = new ServerSocket(8000);
ServerSocket servSocksub = new ServerSocket(5000);
try {
while (true) {
Server servpub = new Server(servSockpub.accept(),++pubNumber);
servpub.start();
System.out.print("\nThe server is running on listen port "+ servSockpub.getLocalPort());
Server servsub = new Server(servSocksub.accept(),++subNumber);
servsub.start();
System.out.print("\nThe server is running on listen port "+ servSocksub.getLocalPort());
}
} finally {
servSockpub.close();
servSocksub.close();
}
}
}
publisher code
package serverclient;
import java.net.*;
import java.io.*;
public class Publisher {
public static void main (String [] args) throws IOException{
Socket sock = new Socket("127.0.0.1",8000);
// reading from keyboard (keyRead object)
BufferedReader keyRead = new BufferedReader(new InputStreamReader(System.in));
// sending to client (pwrite object)
OutputStream ostream = sock.getOutputStream();
PrintWriter pwrite = new PrintWriter(ostream, true);
InputStream istream = sock.getInputStream();
BufferedReader receiveRead = new BufferedReader(new InputStreamReader(istream));
System.out.println("Start the chitchat, type and press Enter key");
String receiveMessage,sendMessage;
while(true)
{
sendMessage = keyRead.readLine(); // keyboard reading
pwrite.println(sendMessage); // sending to server
pwrite.flush(); // flush the data
if((receiveMessage = receiveRead.readLine()) != null) //receive from server
{
System.out.println(receiveMessage); // displaying at DOS prompt
}
else{
System.out.print("Null");
}
}
}
}
subscriber
package serverclient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Subscriber {
public static void main (String [] args) throws IOException{
Socket sock = new Socket("127.0.0.1",5000);
// receiving from server ( receiveRead object)
InputStream istream = sock.getInputStream();
BufferedReader receiveRead = new BufferedReader(new InputStreamReader(istream));
System.out.println("Recive side");
String receiveMessage, sendMessage;
while(true)
{
System.out.print("Hey man " + receiveRead.readLine() + "\n");
if((receiveMessage = receiveRead.readLine()) != null) //receive from server
{
System.out.println(receiveMessage); // displaying at DOS prompt
}
else{
System.out.print("Null");
}
}
}
}
Any help is appreciated. I just want to figure out why subscriber is not reciveing message
There are many possibilities to handle realm time communication issues. I myself prefer the use of Events / EventListeners.
Currently in your program there is no communication between the Server as such and the threads which handle the subscriber connection.
Also on a side node: even with a proper communication between publisher connection threads and subscriber connection threads it won't work now since you are using the same Server class. This does not only violate the Single-Responsibility-Principle but will also prevent the server from ever sending a message to the Subscriber.
Let's say you have establish a connection and your server class is now connected with the subscriber. What will happen?
The subscriber will loop until there is a message on the input stream of his socket. Good that is exactly what we want. But what does the server do? The truth is exactly the same. The first few statements in the try block of your Server's run method are to create a BufferedReader and read from it until a message receives. And now we have a socket on each site which will infinitly wait for some kind of message to arrive (which will obviously never happen since both are waiting for something).
To prevent this you should check if there is anything to read on the stream first:
while ( true )
{
if ( socket.getInputStream().available() != 0 )
{
// reading logic goes here....
synchronized ( this )
{
String clMessage = dStream.readLine();
System.out.println( "\n" + clMessage );
out.println( "Hey the server is sending the message to subscriber" );
}
}
// what shall be done when not reading.
}
Now the second part. If you want to communicate between threads you need to implement some logic to do so. As stated above I love the concept of Listeners so i will show an example where I make use of them:
MessageReceivedListener.java
import java.util.EventListener;
public interface MessageReceivedListener
extends EventListener
{
public void onMessageReceived( String message );
}
Note: The interface does not have to extend EventListener since EventListener
is just a tagging interface. I myself still prefer to have this as a reminder for what purpose the interface is there.
Server.java (excerpt)
// New constructor since we will pass a Listener now. Also new local variable for it.
public Server( Socket socket, int clientNumber, MessageReceivedListener mrl )
{
this.socket = socket;
this.clientNumber = clientNumber;
this.mrl = mrl;
if ( socket.getLocalPort() == 5000 )
System.out.print( "\nSubscriber " + clientNumber + " is connected to the server" );
if ( socket.getLocalPort() == 8000 )
System.out.print( "\nPublisher " + clientNumber + " is connected to the server" );
}
The new constructor provides a way to pass the MessageReceivedListener to the Server object. Alternatively you can alsocreate a setter for it.
synchronized ( this )
{
String clMessage = dStream.readLine();
System.out.println( "\n" + clMessage );
out.println( "Hey the server is sending the message to subscriber" );
mrl.onMessageReceived( clMessage );
}
This is where the magic happens. After whe receive the message we just pass it to the onMessageReceived(String message) method of the listener. But what does it do exactly? This is what we define when creatinga Server object.
Here are two examples, one with anonymous classes (Java 7 and before) and on with lambdas (Java 8 and later).
Example Java 7 and earlier
Server servpub = new Server( servSockpub.accept(), ++pubNumber,
new MessageReceivedListener()
{
#Override
public void onMessageReceived( String message )
{
// call nother local method
// this method would need to be a static method of Server
// because it's in the scope of your server class
sendMessageToSubscribers(message);
}
} );
Here we pass an anonymous class as our MessageReceivedListener object and define it's behaviour (in this case just calling another method which will handle the rest.
Now since our MessageReceivedListener interface does only contain one method we can also see it as a functional interface and therefore use lambdas to shorten the code and improve readability.
Example with Lambda (Java 8 and later)
Server servpub = new Server( servSockpub.accept(), ++pubNumber, Server::sendMessageToSubscribers);
In this specific case we only have one argument which we want to pass to a method and therefore can use a method reference.
How to actually implement the method sendMessageToSubs(String message) is up to you. But you need to keep track of how many Threads with subscriber connections have been created and how you want to reference them.
Related
I am new to working with sockets, and I am working on this project where a connection between my android flutter app and a java server is needed, to do this I am trying socket programming.
The server code is fairly simple, I create a new thread for every client connected and I give them a bunch of URLs, later on, this should be replaced by a query result. here is the java code:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CrawlitServer {
// The port number on which the server will listen for incoming connections.
public static final int PORT = 6666;
//main method
public static void main(String[] args) {
System.out.println("The server started .. ");
// Create a new server socket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(PORT);
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
// Listen for incoming connections and create a new thread for each one
while (true) {
try {
new CrawlitServerThread(serverSocket.accept()).start();
}
catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
public static class CrawlitServerThread extends Thread {
private final Socket socket;
public CrawlitServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
List<String> list = new ArrayList<>();
//assign a value to list
list.add("http://www.google.com");
list.add("http://www.yahoo.com");
list.add("http://www.bing.com");
list.add("http://www.facebook.com");
list.add("http://www.twitter.com");
list.add("http://www.linkedin.com");
list.add("http://www.youtube.com");
list.add("http://www.wikipedia.com");
list.add("http://www.amazon.com");
list.add("http://www.ebay.com");
list.add("http://stackoverflow.com");
list.add("http://github.com");
list.add("http://quora.com");
list.add("http://reddit.com");
list.add("http://wikipedia.org");
try {
// Get the input stream from the socket
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
Scanner scanner = new Scanner(inputStream);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
PrintWriter writer = new PrintWriter(outputStream, true);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println("Received Message from client: " + line);
writer.println(list + "\n");
}
}
catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
Now I run this server and connect to it using sockets in Flutter, I give it the IP address I get from the ipconfig command, and here is the dart code:
import 'dart:async';
import 'dart:io';
//Utilities that manage connections with server sockets.
//ServerUtil Class
class ServerUtil {
static const port = 6666;
static const host = MY_IP_GOES_HERE;
static late Socket socket;
static bool connected = false;
//a list of urls returned by the server
static List<String> urls = [];
//Constructor
ServerUtil() {
//Initialize the socket.
Socket.connect(host, port).then((Socket sock) {
socket = sock;
connected = true;
socket.listen(dataHandler,
onError: errorHandler, onDone: doneHandler, cancelOnError: false);
//send a message to the server.
}).catchError((e) {
print("Unable to connect: $e");
});
}
//Query method that sends a message to the server. The server will return a list of urls.
//The urls will be added to the urls list.
//The urls list will be returned.
static Future<List<String>> query(String userQuery) async {
urls.clear();
//check if socket is connected.
if (connected) {
//send the query to the server.
socket.writeln(userQuery);
await Future.delayed(const Duration(milliseconds: 200));
print(urls);
return urls;
}
//if socket is not connected, wait for 5 seconds and try again.
await Future.delayed(const Duration(milliseconds: 50));
return query(userQuery);
}
//Handles data from the server.
void dataHandler(data) {
//String of received data.
String dataString = String.fromCharCodes(data).trim();
//remove first and last character from the string.
dataString = dataString.substring(1, dataString.length - 1);
//remove all the whitespace characters from the string.
dataString = dataString.replaceAll(RegExp(r'\s+'), '');
urls = dataString.split(',');
}
//Handles errors from the server.
void errorHandler(error, StackTrace trace) {
print(error);
}
//Handles when the connection is done.
void doneHandler() {
socket.destroy();
}
}
This works perfectly fine while using a debug apk running it on my real Note 9 device. The problem however is that when I build a release apk and try it out, nothing happens.
The way I set it up is that I wait for the query method in an async and then I send the result to a new screen and push that screen into the navigator.
But in the release apk nothing happens, the new screen doesn't load.
So this leads me to my first question:
Is there a way to debug a release apk? see what exceptions it throws or print some stuff to console?
I have the server running on my Laptop, and the app runs on my phone which is on the same WIFI network.
My second question is:
Do I need to enable some sort of option with my router or my laptop to allow my phone to connect? it does connect in debug mode without any modifications
I tried some random things, like using 'localhost' instead of my IP, as I would normally connect say with a java client for example, but it didn't work.
My last question is:
Does the release apk or like android OS prevent connections to local hosts, maybe because it thinks it is not secure? but then it still connects in debug mode.
Thank you for your time.
im making a P2P chat program. for this i use UDP datagrams. but im having some problems.
sometimes the program works without any problems. but most of the times only 1 of the 2 people recieve the message or sometimes neither of the 2 people get a message. im thinking about going to TCP but i want to keep it P2P so no central server.
my code:
package herexChatProg;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import javax.swing.JOptionPane;
import login.MainScreen;
public class MessageSender extends Thread {
private int Port;
private String recIP;
private final static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
private MainScreen Screen;
private DatagramSocket ds = null;
private DatagramPacket dp = null;
public MessageSender(MainScreen m, String ip, int port) throws Exception {
recIP = ip;
Port = port;
Screen = m;
System.out.println("chat program: IP address: " + recIP + " port " + Port);
start();
}
public void run() {
try {
// open DatagramSocket to receive
ds = new DatagramSocket(Port);
// loop forever reading datagrams from the DatagramSocket
while (true) {
byte[] buffer = new byte[65000]; // max char length
dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);
String s = new String(dp.getData(), 0, dp.getLength());
Screen.writeText(s);
// System.out.println("UDP datagram length " + s.length() + "
// from IP " + dp.getAddress() + " received: " + s);
}
} catch (SocketException se) {
System.err.println("chat error (Socket Closed = good): " + Se.getMessage());
JOptionPane.showMessageDialog(null, "Please check your connection or try to log on again");
} catch (IOException se) {
System.err.println("chat error: " + se.getMessage());
}
}
public void Stop() {
if (ds != null) {
ds.close();
ds = null;
}
}
public boolean sendMessage(String message) throws IOException {
try {
System.out.println("Sending to " + recIP + " socket " + Port + " data: " + message);
byte[] data = message.getBytes();
DatagramSocket theSocket = new DatagramSocket();
DatagramPacket theOutput = new DatagramPacket(data, data.length, InetAddress.getByName(recIP), Port);
theSocket.send(theOutput);
Screen.writeText(message);
return true;
} catch (IOException e) {
return false;
}
}
}
if any of you spot the problem or can help me that would be great
thanks DenTilloZie
if any of you spot the problem or can help me that would be great
The "problem" of not all messages reaching their destination is normal, it's because UDP is unreliable. It isn't due to your code (well due to the fact you're using UDP instead of TCP).
If you want to be sure that each message arrives at its destination you have 2 possibilities. You could use TCP instead of UDP as TCP guarantees each message arrive (and guarantees even more). If you really want to continue with UDP you will have to send an acknowledge (to the original sender of the message) when receiving a message. When a sender receives the acknowledge he can be sure the message arrived at its destination. However there are a lot of extra problems you should fix if you use UDP (message order, ...). So i would just recommend to use TCP instead of reinventing the wheel.
im thinking about going to TCP but i want to keep it P2P so no central server.
This will be hard to achieve. There are different possibilities for implementing a Peer-to-peer system :
With a central coordinater
By flooding
By distributed hash tables
The first approach is the simplest but is not possible as you explicitly want no central server. But the other approaches are considerably more difficult.
I basically have an application that lets customers make reservations to a cinema for a movie. It also has admins that have control over the users database and content admins that take care of the movie and viewings database.
At this point, we are not required to use an actual database but to read from and write to files. We have to do this through sockets. The files are on the server and the client gets or sends the data through the connection between the sockets.
There are different java files for the admins, the content admins and the users, each one containing the methods used by each user class. All these java files are on the client side.
I have the following questions.
Is it correct that all the "logic" of the program (the .java files containing the methods) is on the client side?
Do I have to use one socket for the server side and one for the client side? In that case, all methods from the different java files communicate and pass data through the one client socket.
Different methods read from and write to different files. How do I tell the data passing through the socket from the client to the server, that it needs to be written to a specific file? (the same for reading from the appropriate file)
Two more specific examples.
a) There is a method that lets admins add users to the Users.txt file. The admin gives the userId (used to differentiate between admins, content admins and users), name, username and password as arguments to the addUser() method through the main method. How do I send the data through the socket and write them to the correct file? Is there a correspondind method on the server side that has a writer that writes the data to the file? Moreover, do I send the data all as a single line, or as different parts?
public void createUser(int userId, String name, String username, String password){
try{
PrintWriter Writer = new PrintWriter(new BufferedWriter(new FileWriter("Users.txt", true)));
boolean appendToFile = true;
if (appendToFile) {
Writer.println(userId + " " + name + " " + username + " " + password);
}
System.out.println("The user "+getUsername()+" was created!");
Writer.close();
}
catch (IOException e) {
}
}
b) Another method enables the customer to search for films based on a keyword. We need to search each line of the Films.txt file (it has the structure filmId(int);filmCategory(enum);filmTitle(string);filmDesription;). The searchViewings() method sends the keyword that the user gave, through the socket, and on the server side it needs to search each line of the file for the keyword in the film titles. Again, is there a correspondind method that contains the logic for searching each line of the file? Else, how does the server side with only the keyword available knows what to do with it?
public void searchViewings(String keyword){
File inputFile = new File("Provoles.txt");
String currentLine = null;
boolean flag = false;
try{
BufferedReader Reader = new BufferedReader(new FileReader(inputFile));
System.out.println("The movies that contain the keyword '"+keyword+"' have the following available viewings:");
while ((currentLine = Reader.readLine()) != null) {
String s = currentLine;
String delims = ";";
String[] tokens = s.split(delims);
if (tokens[1].indexOf(keyword) != -1){
flag = true;
System.out.println("The movie with Film ID '"+tokens[0]+"' and Film Title '"+tokens[1]+"' has an available viewing at the cinema with ID '"+tokens[2]+"'.");
}
}
if (flag == false){
System.out.println("There is no movie containing the current keyword.");
}
Reader.close();
}
catch (IOException e) {
}
}
The above code was like this before any socket was implemented.
At last, is there an example that uses multiple files that I can read or run?
Is it correct that all the "logic" of the program (the .java files containing the methods) is on the client side?
No not really there has to be somelogic on the server side aswell, written in Java or in another language. Or else there is no way the server can read the file and do logic or send the file to the client.
Do I have to use one socket for the server side and one for the client side? In that case, all methods from the different java files communicate and pass data through the one client socket.
You don't have to, for this you will ofcourse need atleast one socket but you could also use more than one socket. For example a socket that the admins use and a socket that the clients use.
Different methods read from and write to different files. How do I tell the data passing through the socket from the client to the server, that it needs to be written to a specific file? (the same for reading from the appropriate file)
You could send a header through the socket saying something like: read/file1 or write/file4. Or something similar, the point is just sending some data telling the server what to do.
At last, is there an example that uses multiple files that I can read or run?
I don't have one as of this moment but I'll google a bit and update this later if I find one.
I hope this helps :)
To answer your first question, you can either store the app logic on the client (aka thick/fat client) or on the server (thin client). From what I know, there's no one exact answer to which is "better". It really depends on your app. Use thin client (logic stored on the server) if you want the majority of the processing to be done by the server (this is desired for devices with limited processing power, like smart phones). Use fat clients if you'd prefer to perform more of the processing on the clients or if you have limited bandwidth to access your server. There are many articles about fat vs thin clients. Here's one that you might find useful.
I'm a little rusty on sockets, so you might want to take the advice of the other answer, but from what I remember each client will have 1+ socket, and the server will also have 1+ (depending on how you choose to implement your connection) socket. Both client and server will use the same port number. See this article for some simple examples. When I experimented with them, I used ServerSocket for the server and Socket for the client. Check out the different examples in the above link for ideas. If you have additional questions, let me know and I'll do my best to elaborate.
Here's a simple project using sockets and files to read to and write from that I did a while ago. Hopefully viewing this code will clarify the questions you have with your own code. Due to the time constraints, I didn't convert it to include the code snippets you've provided, but if you're still stuck with your own code after taking a look at mine, I'll see what I can do.
A few things to note if you run this code:
This project uses server and client GUIs that are a little messy (I'm not very good at designing GUIs), but the functionality should still be useful.
You need to provide the same port number as a command line argument for both the server and client. You can do this in Eclipse via Run button dropdown -> Run configurations... -> arguments tab ->typing a port number (I used 12345) -> click run). Do this for both the server and client.
Make sure to run the server before you run the client
This example only reads from files. There's no writing functionality.
Once the client has successfully started, type the name of the file you want to read from (ie: readfile1.txt) including the file extension.
This uses relative path names starting from the root project directory so if your Users.txt file is in your src folder, you'd type "src/Users.txt".
Type the file name in the client's input field at the top of the client GUI to have the entire contents of that file printed below. You can type as many file names as you want one at a time.
Server code
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class FileServer extends JFrame {
//main function
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
//String file = args[1];
FileServer server = new FileServer(port);
server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
server.runServer();
}
//FileServer class declarations
private File file; //for this example, the file is stored in the root project directory and includes the file extension (ie: .txt, etc)
private ServerSocket ss;
private Socket connection;
private JTextField field;
private JTextArea displayArea;
private int portNum;
private ObjectOutputStream oos;
private ObjectInputStream ois;
public FileServer(int port) {
super("Server");
//file = new File(f); //sent from client or done here?
portNum = port;
field = new JTextField();
field.setEditable(false);
field.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent event) {
sendData(event.getActionCommand());
field.setText("");
}
}); //ends addActionListener
add(field, BorderLayout.NORTH);
displayArea = new JTextArea();
add(new JScrollPane(displayArea));
setSize(500, 300);//size of JFrame
setVisible(true);
}//end constructor
/**
* code that executes the server obj. Think of it as FileServer's main(). This is called from main().
*/
public void runServer() {
try {
ss = new ServerSocket(portNum, 100); //creates server socket with port # specified by user and a queue of 100
while (true) { //infinite loop to continually listen for client connections
try {
waitForConnection(); //wait for client connections
getStreams(); //get I/O streams
processConnection();
}
catch (EOFException e) {
e.printStackTrace();
}
finally {
closeConnection();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}//end runServer
/**
* creates socket obj to interact with client. Socket created when connection with client made
* #throws IOException
*/
public void waitForConnection() throws IOException {
displayMessage("Waiting for connection\n");
connection = ss.accept(); //returns socket obj when connection made with client
displayMessage("Connection made with " + connection.getInetAddress().getHostName());
}//end waitForConnection
/**
* gets IO stream objs for FileServer class
*/
public void getStreams() {
try {
oos = new ObjectOutputStream(connection.getOutputStream());
oos.flush();
ois = new ObjectInputStream(connection.getInputStream());
}
catch (IOException e) {
e.printStackTrace();
}
displayMessage("\n Got both IO streams \n");
}//end getStreams
/**
* receives filename sent from client and creates file
*/
public void processConnection() throws IOException {
sendData("Connection successful");
setTextFieldEditable(true);
do { //added do while for testing
try {
String message = (String) ois.readObject(); //should read in filename then create file obj
displayMessage("\n " + message + " received from client\n");
displayMessage("Type in absolute path of file in text field above");
file = new File(message);
if(!file.exists()) {
sendData("File not found");
}
else {
Scanner cin = new Scanner(file);
while(cin.hasNextLine()) {
message = cin.nextLine();
sendData(message);
}
cin.close();
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
} while(true);
}//end processConnection
/**
* closes IO streams
*/
public void closeConnection() throws IOException {
displayMessage("\nClosing connections\n");
setTextFieldEditable(false);
oos.close();
ois.close();
connection.close();
}//end closeConnection
/**
* sends message to client
* #param message
*/
public void sendData(String message) {
try{
oos.writeObject(message);//this is what sends message
oos.flush();
displayMessage("\n in sendData: " + message + "\n");
}
catch(IOException e) {
displayArea.append("\n Error writing object");
e.printStackTrace();
}
}//end sendData
public void displayMessage(final String message) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
displayArea.append(message);
}
});//end SwingUtilties
}
private void setTextFieldEditable( final boolean editable )
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run() // sets enterField's editability
{
field.setEditable( editable );
} // end method run
} // end anonymous inner class
); // end call to SwingUtilities.invokeLater
} // end method setTextFieldEditable
}
Client code
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class FileClient extends JFrame
{
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
String fileName = args[1]; //must use absolute path for filename
FileClient app = new FileClient("127.0.0.1", port, fileName);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
app.runClient();
}
private JTextField enterField; // enters information from user
private JTextArea displayArea; // display information to user
private ObjectOutputStream output; // output stream to server
private ObjectInputStream input; // input stream from server
private String message = ""; // message from server
private String chatServer; // host server for this application
private Socket client; // socket to communicate with server
private int portNum;
private String fileName;
private File file;
// initialize chatServer and set up GUI
public FileClient( String host, int port, String fileName )
{
super( "Client" );
portNum = port;
this.fileName = fileName;
//file = new File(fileName);
chatServer = host; // set server to which this client connectsS
enterField = new JTextField(); // create enterField
enterField.setEditable( false );
enterField.addActionListener( //need to find a way to send fileName to server without having to type it in
new ActionListener()
{
// send message to server
public void actionPerformed( ActionEvent event )
{
sendData( event.getActionCommand() );
enterField.setText( "Messages will be displayed in other text box" );
} // end method actionPerformed
} // end anonymous inner class
); // end call to addActionListener
add( enterField, BorderLayout.NORTH );
displayArea = new JTextArea(); // create displayArea
add( new JScrollPane( displayArea ), BorderLayout.CENTER );
setSize( 500, 300 ); // set size of window
setVisible( true ); // show window
} // end Client constructor
// connect to server and process messages from server
public void runClient()
{
try // connect to server, get streams, process connection
{
connectToServer(); // create a Socket to make connection
getStreams(); // get the input and output streams
processConnection(); // process connection
sendData(fileName); //sends name of file to server to retrieve
displayMessage("Sent request for " + fileName + " to server.");
} // end try
catch ( EOFException eofException )
{
displayMessage( "\nClient terminated connection" );
} // end catch
catch ( IOException ioException )
{
ioException.printStackTrace();
} // end catch
finally
{
closeConnection(); // close connection
} // end finally
} // end method runClient
// connect to server
private void connectToServer() throws IOException
{
displayMessage( "Attempting connection\n" ); //not getting here
// create Socket to make connection to server
client = new Socket( InetAddress.getByName( chatServer ), portNum );
// display connection information
displayMessage( "Connected to: " +
client.getInetAddress().getHostName() );
} // end method connectToServer
// get streams to send and receive data
private void getStreams() throws IOException
{
// set up output stream for objects
output = new ObjectOutputStream( client.getOutputStream() );
output.flush(); // flush output buffer to send header information
// set up input stream for objects
input = new ObjectInputStream( client.getInputStream() );
displayMessage( "\nGot I/O streams\n" );
} // end method getStreams
// process connection with server
private void processConnection() throws IOException //problem possibly due to processConnection being in infinite loop?
{
// enable enterField so client user can send messages
setTextFieldEditable( true );
do // process messages sent from server
{
try // read message and display it
{
message = input.readObject().toString(); // read new message
displayMessage( "\n" + message ); // display message
} // end try
catch ( ClassNotFoundException classNotFoundException )
{
displayMessage( "\nUnknown object type received" );
classNotFoundException.printStackTrace();
} // end catch
} while ( !message.equals( "SERVER>>> TERMINATE" ) );
} // end method processConnection
// close streams and socket
private void closeConnection()
{
displayMessage( "\nClosing connection" );
setTextFieldEditable( false ); // disable enterField
try
{
output.close(); // close output stream
input.close(); // close input stream
client.close(); // close socket
} // end try
catch ( IOException ioException )
{
ioException.printStackTrace();
} // end catch
} // end method closeConnection
// send message to server
private void sendData( String message ) //need to send filename to server
{
try // send object to server
{
output.writeObject(message);
//output.writeObject(fileName); //is writeObject the appropriate write method?
output.flush(); // flush data to output
displayMessage( "\nCLIENT>>> " + message );
} // end try
catch ( IOException ioException )
{
displayArea.append( "\nError writing object" );
ioException.printStackTrace();
} // end catch
} // end method sendData
// manipulates displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
} // end method run
} // end anonymous inner class
); // end call to SwingUtilities.invokeLater
} // end method displayMessage
// manipulates enterField in the event-dispatch thread
private void setTextFieldEditable( final boolean editable )
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run() // sets enterField's editability
{
enterField.setEditable( editable );
} // end method run
} // end anonymous inner class
); // end call to SwingUtilities.invokeLater
} // end method setTextFieldEditable
} // end class Client
I hope this helps.
I am trying to improve the speed at which the sockets transfer information but i am unsure how to do so. the pourpose of the code is to transfer a number, the date, and a short xml which is being sent in the form of a string.
this is the server code
import java.net.*;
import java.io.*;
public class SSocket extends Thread
{
private ServerSocket serverSocket;
public SSocket(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(100000);
}
public void run()
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
while(true)
{
try
{
Socket server = serverSocket.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
int cor=in.readInt();
int i=0;
String transaccion = in.readUTF();
String fecha = in.readUTF();
System.out.println(cor);
System.out.println(transaccion);
System.out.println(fecha);
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
if(transaccion!=null && fecha != null && cor>0){
out.writeInt(cor);
}
else {
out.writeInt(-1);
}
if (i==100){
out.flush();
i=0;
}
i++;
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = 1337;
try
{
Thread t = new SSocket(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
the code for the client is
import java.net.*;
import java.io.*;
public class ClientSocket
{
public static void send(int correl, String transaccion, String fecha)
{
String serverName = "localhost";
int port = 1337;
try
{
Socket client = new Socket(serverName, port);
int i=0;
OutputStream outToServer = client.getOutputStream();
DataOutputStream out =
new DataOutputStream(outToServer);
out.writeInt(correl);
out.writeUTF(transaccion);
out.writeUTF(fecha);
InputStream inFromServer = client.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
int corin=in.readInt();
if(corin>0){
Envio.updater(corin);
}
else {
}
if (i==100){
out.flush();
i=0;
}
i++;
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
i have done some reading on the mater and it seems that posible solutions are to use either a buffer or swich to a datagram. however my experience on working with sockets is rather limited and i am unsure which would be best to use for this situation or if there is another option i havent yet considered. this code will be moving many transactions and i wish to do it in as short time as posible.
thanks in advance
ps. sorry for my bad english it is not my first language
Datagrams imply UDP, which is an unreliable delivery protocol so you're not guaranteed to get all content. That's probably not what you want; I'd stay with plain Sockets (which use TCP, which has reliable delivery).
Will the same client be calling send() repeatedly and connecting to the same server each time? That is, will there be many messages going across a single connection, or will each message be to a different server, with only a single message (or only a few) going to each of the many servers? If there's just one server that a client is going to connect to and if a given client is going to send lots of messages, you should keep the Socket open between send() calls; setting up and tearing down Sockets is expensive, so you're paying a high price for making a new connection each time.
Also, your server appears to only be able to handle a single connection at a time: you accept a connection, read from it, and then close it and accept a new one. So to make this work for more than one client, you'll need to separate the logic for accepting connections onto a different thread from the logic that reads data. If you'll only have a few clients at a time, you can just start a new thread to read from each socket as you create it for a new client; if you'll have lots of clients (thousands), you'll probably need to look at NIO for its ability to service multiple sockets from a single thread. But I suspect you're a long way from having that problem, if you ever do, so I'd just spawn a new thread for each socket.
i have the follwoing code of proxy server. IS if the right approach? Will this be able to handel load/trafffic if deployed comerially??
package proxyserver;
import com.sun.corba.se.spi.activation.Server;
import java.net.* ;
import java.io.* ;
import java.lang.* ;
import java.util.* ;
/**
*
* #author user
*/
public class Main {
/**
* #param args the command line arguments
*/
// Variable to track if an error occurred
boolean errorOccurred = false;
//Variables for the host and port parameters
public static void main(String[] args) {
// TODO code application logic here
int localPort = -1;
int remotePort = -1;
String remoteHost = "www.youtube.com";
System.out.print("dwdsw");
Integer parseLocalPort = new Integer(555);
Integer parseRemotePort = new Integer(80);
localPort =80 ;
remotePort = 80;
//Create a listening socket at proxy
ServerSocket server = null;
try
{
server = new ServerSocket(localPort);
}
catch(IOException e)
{
System.err.println("Error: " + e.getMessage());
System.exit(-1);
}
//Loop to listen for incoming connection,
//and accept if there is one
Socket incoming = null;
Socket outgoing = null;
while(true)
{
try
{
// Create the 2 sockets to transmit incoming
// and outgoing traffic of proxy server
incoming = server.accept();
outgoing = new Socket(remoteHost, remotePort);
// Create the 2 threads for the incoming
// and outgoing traffic of proxy server
ProxyThread thread1 = new ProxyThread(incoming, outgoing);
thread1.start();
ProxyThread thread2 = new ProxyThread(outgoing, incoming);
thread2.start();
}
catch (UnknownHostException e)
{
System.err.println("Error: Unknown Host " + remoteHost);
System.exit(-1);
}
catch(IOException e)
{
//continue
System.exit(-2);;
}
}
}
}
now proxy classs
package proxyserver;
/**
*
* #author user
*/
import java.net.* ;
import java.io.* ;
import java.lang.* ;
import java.util.* ;
class ProxyThread extends Thread
{
Socket incoming, outgoing;
ProxyThread(Socket in, Socket out)
{
incoming = in;
outgoing = out;
}
// Overwritten run() method of thread,
// does the data transfers
public void run()
{
byte[] buffer = new byte[5000];
int numberRead = 0;
OutputStream toClient;
InputStream fromClient;
try{
toClient = outgoing.getOutputStream();
fromClient = incoming.getInputStream();
while(true)
{
numberRead = fromClient.read(buffer, 0, 50);
if(numberRead == -1)
{
incoming.close();
outgoing.close();
}
String st = new String(buffer,"US-ASCII");
System.out.println("\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\nXXXXXXXXXXXXXXXX\n\n" + st);
toClient.write(buffer, 0, numberRead);
}
}
catch(IOException e)
{
}
catch(ArrayIndexOutOfBoundsException e)
{
}
}
}
[ OK ... enough teasing :-) ]
It looks like it should work, though:
The stuff that you print to System.err in the Proxy class may be mangled. (As I said before, you cannot just assume that every web page is encoded in ASCII!!)
You should probably be reading much more than 50 bytes at a time .... especially if you want high throughput.
Your main class probably should be using a thread pool rather than creating and throwing away threads. And you probably should put an upper bound on the number of threads you want to allow at any given time.
You probably need to do something about servers that take a long time to deliver their responses, etcetera.
Finally, in response to this:
Will this be able to handle the
load/traffic if it is deployed commercially??
It is impossible to say how much load you could pump through this program. For a start, it will depend on your processor and network interface hardware.
It looks about right in principle but you should take a look at an open source version like TCP Proxy for pointers on maximizing throughput, increasing resilience, etc.