I have a java server which is using TCP and sockets to connect to an Android application (the client) and sends strings (currently taken in from a scanner object) which are then displayed as notifications by the client.
heres the Server code without all the imports.
public class Server {
// define our Main method
public static void main(String[] args) throws IOException {
// set up our Server Socket, set to null for the moment.
ServerSocket serverSocket = null;
boolean isConnected = false;
// Lets try and instantiate our server and define a port number .
try {
serverSocket = new ServerSocket(6789);
isConnected = true;
System.out.println("*** I am the Server ***\n");
// make sure to always catch any exceptions that may occur.
} catch (IOException e) {
// always print error to "System.err"
System.err.println("Could not listen on port: 6789.");
System.exit(1);
}
// We always want to check for connection from Clients, so lets define
// a for ever loop.
for (;;) {
// define a local client socket
Socket clientSocket = null;
// lets see if there are any connections and if so, accept it.
try {
clientSocket = serverSocket.accept();
// don't forget to catch your exceptions
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Prepare the input & output streams via the client socket.
// fancy way of saying we want to be able to read and write data to
// the client socket that is connected.
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
PrintWriter outToClient = new PrintWriter(clientSocket.getOutputStream(),
true);
while (isConnected) {
// read a sentence from client
String hiFromClient = inFromClient.readLine();
// Set up the logging system and timestamp and log message.
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter=
new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss");
String dateNow = formatter.format(currentDate.getTime());
try{
// Create file
File fstream = new File("log.txt");
FileWriter out = new FileWriter(fstream);
out.write(hiFromClient + " " + dateNow);
//Close the output stream
out.close();
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
// Print the client sentence to the screen
System.out.println("The Client said: "+hiFromClient);
// Reply to the client
Scanner scanner = new Scanner(System.in);
String sentence = scanner.nextLine();
outToClient.println(sentence );
System.out.println("The Server said: " + sentence);
}
// always remember to close all connections.
inFromClient.close(); // the reader
outToClient.close(); // the writer
clientSocket.close(); // and the client socket
}
}}
Growl uses port 23053 for notification forwarding. What i am hoping to do is to listen in on 23053 and send anything in from that as a string to the client connected at 6789. Sadly Growl binds the port number so a new Socket connection cant be made.
Any one have any ideas on how i could get notifications from the port number growl uses or even just use growl as the server for the client itself (the client's code is very similar to the servers by the way just using Socket instead of ServerSocket)
Any help on this would be greatly appreciated, its wrecking my brain
All the best,
Patrick.
There is a round-about way you could do it. If you are desperate, read on:
Growl can forward any notifications it receives to another machine running Growl (configured on the Network tab). Growl uses the GNTP protocol (a TCP-based protocol: http://www.growlforwindows.com/gfw/help/gntp.aspx) to forward the messages. The trick is that that 'other machine running Growl' doesnt have to really be another machine OR running Growl per se, it just needs to appear to Growl that it is. Growl (on the Mac, which is what I assume you are using) will automatically detect any other machines on the network running Growl (using Bonjour and looking for the _gntp._tcp service name), so if your server advertises itself as supporting the GNTP protocol, Growl should show it in the list of available destinations. (Growl for Windows also lets you manually add a hostname/port to forward to, but I dont believe the Mac version currently allows that).
So then you could configure Growl to forward notifications to your server using its already-built-in capabilities. You would have to implement code in your server to receive the GNTP packets (the format is very similar to HTTP headers) and parse them. Then you could forward the notifications using your current server code.
Still with me? I did say it was round-about, but it is not only technically possible, but I have built a Growl-impersonating daemon before so that I could have notifications forwarded from Growl to my custom code. Not suggesting it as the best idea, but just an alternative since you asked.
Related
I've just started with both java and networking with servers and clients. Although i understand the basics of whats going on, i was struggling to put it all together and do what i wanted to do in the title.
I was able to make this to send a message to the server, however i was wondering how i'd turn the message into a input string from the user, and also how id send multiple messages between the client and server
thanks
SERVER
import java.io.*;
import java.net.*;
public class Server {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
//Remember to close the socket once we have finished with it.
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
CLIENT
import java.io.*;
import java.net.*;
public class Client {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
//ServerIP:- IP address of the server.
String serverIP = "localhost";
try{
//Create a new socket for communication
Socket soc = new Socket(serverIP,portNumber);
//Create the outputstream to send data through
DataOutputStream dataOut = new DataOutputStream(soc.getOutputStream());
//Write message to output stream and send through socket
dataOut.writeUTF("Hello other world!");
dataOut.flush();
//close the data stream and socket
dataOut.close();
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
There are some "problems" with your code.
You should only close the ServerSocket if you are done.
You should handle the newly connected client inside a thread to allow multiple clients to simultaniously "send messages".
1.
you could easily wrap your code inside an while loop.
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
//Remember to close the socket once we have finished with it.
soc.close();
}
Now your programm should continue to accept clients. But only one at a time. You can now terminate the Server by stopping the programm or by changing the someCondition to false and accepting the next client.
A bit more advanced would be, to shutdown the ServerSocket to stop the programm and catching the exception inside the while loop.
2.
To allow multiple clients to be handled simultaniously, you should pack the handle part into another Thread.
private ExecutorService threadPool = Executors.newCachedThreadPool();
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console in a new Thread.
threadPool.submit(() -> {
DataInputStream dataIn = new
DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
}
//Remember to close the socket once we have finished with it.
soc.close();
}
The part inside the threadPool.submit block could be specified as an custom instance of the Runnable interface of as an method, to call it using method reference.
I assumed you are knowing about ThreadPools. They have multiple advantages over Threads
This should get you going for any number of clients.
Note: This is not good designed, but it is for demonstrational porpurses only.
I have a server-client application set. (HOMEWORK)
So far I have figured out how to have multiple clients connect to the server and have the server aggregate the messages the clients send, as well as having the server send the client's message back to the client and displaying it in the chat pane.
My issue is trying to send a message to multiple clients. I am only allowed to use ServerSocket and Socket libraries.
Say I have 2 clients connected to the server. One client sends a message, the message is displayed in the client's chat. The second client sends a message, the first client does NOT receive it, and the second client's chat window displays the first client's message.
Essentially the server is sending the most recent message that the respective client has not displayed in the chatbox, and I have no idea why or how.
Code for server-to-client communication :
Class CommunicationThread extends Thread {
//Vector containing all client sockets currently connected
//Held offsite, here for clarity
public Vector<Socket> socketVector;
public CommunicationThread (Socket clientSoc, Server ec3, Vector<Socket>socketVectorg)
{
//add new socket to vector, start thread
clientSocket = clientSoc;
socketVectorg.add(clientSocket);
this.socketVector = socketVectorg;
gui = ec3;
}
public void run()
{
System.out.println ("New Communication Thread Started");
try {
//Client's chat box (output)
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
//Input line from client
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
gui.history.insert(inputLine + "\n", 0);
//*************HERE IS MY ISSUE*******************
for(Socket s : socketVector){
out = new PrintWriter(s.getOutputStream(),
true);
out.println(inputLine);
}
if (inputLine.equals("Bye."))
break;
if (inputLine.equals("End Server."))
gui.serverContinue = false;
}
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
System.err.println("Problem with Communication Server");
//System.exit(1);
}
}
}
I know I am overwriting "out" but I don't think that is my issue so it is in my code while I am testing.
My issue is marked in the code above. The vector accurately stores the socket ID, and since I am creating a new PrinterWriter based on the vector, I would only assume that it would get the output field of the respective client, but it does not.
My intuition is that it is a problem with threading or closing the output, but I honestly don't know.
Any recommendations are appreciated.
Your problem it seems to me is that you want to do the input and output work on the client socket all in the same place, and there's no need for that. The client socket's output stream can be written to in the GUI thread, and all in one place. You can keep a collection of the output streams if need be and when you want to reply to all, iterate through the collection (probably a HashMap<String, OutpuStream> where the String is some client identifier) and send the messages.
The problem is I only found a little description about port 17, also known as "Quote of the date" port. Useless port, does nothing but display a quote which is less than 512 ASCII characters. Could someone give me more information about how to listen to port 17 in Java? I have established a server client socket using port:6017.
Here is the code:
public class DateServer {
public static void main(String[] args) {
try {
ServerSocket sock = new ServerSocket(6017);
// now listen for connections
while (true) {
Socket client = sock.accept();
// we have a connection
PrintWriter pout = new PrintWriter(client.getOutputStream(), true);
// write the Date to the socket
pout.println(); // I know something must happens here!!!
// close the socket and resume listening for more connections
client.close();
}
} catch (IOException ioe) {
System.err.println(ioe);
}
}
}
The system runs in Linux and this code is the server end of the program. I am working on the Client part, and try to make the server do the same thing like port 17 then have a client to receive the "quote of the day" from the server.
Ports less than 1024 are privileged and require escalated permissions to run. Run your program as an administrator of your machine with the port set to 17.
I have TCP server-client application. It works but sometime something happens. Client connects to server but server says he doesn't accepted him.
Server side code:
while(!stopped){
try {
AcceptClient();
} catch(SocketTimeoutException ex){
continue;
} catch (IOException ex) {
System.err.println("AppServer: Client cannot be accepted.\n"+ex.getMessage()+"\n");
break;
}
...
private void AcceptClient() throws IOException {
clientSocket = serverSocket.accept();
clientSocket.setSoTimeout(200);
out = new ObjectOutputStream(clientSocket.getOutputStream());
in = new ObjectInputStream(clientSocket.getInputStream());
System.out.println("Accepted connection from "+clientSocket.getInetAddress());
}
Client side code:
try {
socket = new Socket(IPAddress, serverPort);
socket.setSoTimeout(5000);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
} catch (IOException e1) {
sendSystemMessage("DISCONNECTED");
sendSystemMessage(e1.getMessage());
return;
}
sendSystemMessage("CONNECTED");
If client connects the message:
Accepted connection from ... appears. But sometimes it doesn't appear
even if client sends message "CONNECTED"
Server is still runing the loop trying to get client and it is catching socketTimeoutException. Client is connected, sends message and waits for response.
I suspect a missing 'flush' inside your client's 'sendSystemMessage()'.
Unfortunately the constructor of ObjectInputStream attempts to read a header from the underlying stream (which is not very intuitive IMHO). So if the client fails to flush the data - the server may remain stuck on the line "in = new ObjectInputStream(socket.getInputStream())"...
As a side note it's usually better for a server to launch a thread per incoming client, but that's just a side remark (plus it obviously depends on requirements).
I found the problem. The communication on my net is too slow so it timeouts in getting inputstream. The solution has two parts. Flushing outputstream before getting inputstream. And set socket timout after streams are initialized.
serverside:
clientSocket = serverSocket.accept();
out = new ObjectOutputStream(clientSocket.getOutputStream());
out.flush()
in = new ObjectInputStream(clientSocket.getInputStream());
clientSocket.setSoTimeout(200);
I am trying to send data from a C#.NET (Windows Application) program to a Java (Android App) program and vice versa, via TCP connection through Wifi. Till now I am success to send data from Java to C#, but unable to do so from C# to Java.
Following is the Java code, I used to create a connection and receive data:
ServerSocket serverSocket = null;
DataInputStream socketInputStream;
while (true) {
try {
String localIPAddr = getLocalIPAddress();
InetSocketAddress ipEndPoint = new InetSocketAddress(
InetAddress.getByName(localIPAddr), 8222);
serverSocket = new ServerSocket();
serverSocket.bind(ipEndPoint, 4);
workerSocket = serverSocket.accept();
socketInputStream = new DataInputStream(
workerSocket.getInputStream());
inputText.setText(socketInputStream.readUTF());
} catch (Exception ex) {
throw ex;
}
}
Here getLocalIPAddress() method returns the IP Address of the Android Device.
Following is the C# code in Windows Application to connect to the Android's IP Address (192.168.1.6) and send data to it:
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
void button1_Click(object sender, EventArgs e)
{
try
{
if (!clientSocket.Connected)
clientSocket.Connect(IPAddress.Parse("192.168.1.6"), 8222);
clientSocket.Send(Encoding.UTF8.GetBytes(txtInput.Text));
}
catch (Exception ex)
{
throw ex;
}
}
Well, client (C#) is failing to connect to the server (Java) That means data is not leaving from client. But it will, if it get connected. Please tell me what am I missing and where am I mistaken. :)
After you have launched your android app and it is connected to the wifi, did you try to do a ping to the ip where the application is launched.
ping 192.168.1.6
If the IP is accessible from the workstation where C# app is running, try to perform a telnet on the IP and Port of the android ip, to see whether it works or not.
telnet 192.168.1.6 8222
If either of the two steps fail then could be a problem in the wifi network. As i have noticed many times the firewall of the routers filters out all the ports except 8080 and 80. So you would need to open the ports on the router.
Did you try to do this?
Runnable showmessage = new Runnable() {
public void run() {
myTextView.setText(membervariabletext);
}
};
and from your thread, after the readUTF(), call
runOnUiThread(showmessage);
Found this here
Well, I have solved this myself, but of course Dilberted has helped me a little bit. I thank him for what he has provided. :)
Check out the solved Java code below:
ServerSocket serverSocket = null;
Socket workerSocket;
DataInputStream socketInputStream;
try {
if (serverSocket == null) {
// No need to get local IP address and to bind InetSocketAddress.
// Following single line make it very simple.
serverSocket = new ServerSocket(8222, 4);
workerSocket = serverSocket.accept();
}
// When data are accepted socketInputStream will be invoked.
socketInputStream = new DataInputStream(
workerSocket.getInputStream());
/* Since data are accepted as byte, all of them will be collected in the
following byte array which initialised with accepted data length. */
byte[] rvdMsgByte = new byte[socketInputStream.available()];
// Collecting data into byte array
for (int i = 0; i < rvdMsgByte.length; i++)
rvdMsgByte[i] = socketInputStream.readByte();
// Converting collected data in byte array into String.
String rvdMsgTxt = new String(rvdMsgByte);
// Setting String to the text view.
receivedMsg.setText(rvdMsgTxt);
} catch (Exception ex) {
throw ex;
}
Note that a separate thread is to be used to run this code in background.