I have the code below which creates a socket UDP-style. I run and compile the code and it works just fine. If I then use "netcat -u " I am able to send messages from the client to the server but not the other way around. So what I want and what I have been trying to do is to read from stdin and printing it(all this running in a second thread). Making it a two-way communication. Anyone know what I need to fix? Thanks in advance.
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class NetcatUDP {
public static void main(String[] args) throws IOException {
int port = Integer.parseInt(args[0]);
byte[] buffer = new byte[65536];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
DatagramSocket socket = new DatagramSocket(port);
new Thread() {
#Override
public void run() {
// Read from stdin and send somehow?
}
}.start();
while (true) {
socket.receive(packet);
System.out.println(new String(packet.getData()).trim());
}
}
}
UDP is a connection-less protocol, which means you can send a message to anyone and receive a message from anyone with a single socket.
For the simple example you're using, you can actually use the same program for both endpoints. Besides reading in the local port number from the command line, read in the remote IP address and port as well. Then in your thread, you read from stdin using Console.readLine(), construct a DatagramPacket with the line read from the console, remote IP, and remote port, and send it with the existing socket you have.
Related
I'm trying to make a chat program where the client and the server can chat with each other on different networks (not localhost) I'm currently faced with a problem that i don't know how to solve.
For some reason, the client and the server can't connect to each other, when i write a message to the server with the client, nothing pops up on the server. The tests were run on two different computers, on different networks (Mobile data and Ethernet)
I've used the public ip from my ethernet in the code, and portforwarded it with the matching port number in the code. The server is running on the portforwarded network.
This is my code:
CLIENT:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatClient {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
DatagramSocket client = new DatagramSocket(7000);
byte[] receivedData = new byte[1024];
byte[] sentData;
InetAddress address = InetAddress.getByName(" PUBLIC IP IS HERE, won't show it for obvious reasons ");
while (true) {
String message = scanner.nextLine();
sentData = message.getBytes();
DatagramPacket dp1 = new DatagramPacket(sentData, sentData.length, address, 7000);
client.send(dp1);
DatagramPacket dp4 = new DatagramPacket(receivedData, receivedData.length);
client.receive(dp4);
String receivedMessage = new String(dp4.getData());
System.out.println(receivedMessage);
}
}
}
SERVER:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatServer {
public static void main(String[] args) throws IOException {
DatagramSocket server = new DatagramSocket();
Scanner scanner = new Scanner(System.in);
byte[] receivedData = new byte[1024];
byte[] sentData;
while (true) {
DatagramPacket dp2 = new DatagramPacket(receivedData, receivedData.length);
server.receive(dp2);
String storedData = new String(dp2.getData());
System.out.println(storedData);
InetAddress getIP = dp2.getAddress();
int port = dp2.getPort();
String sentMessage = scanner.nextLine();
sentData = sentMessage.getBytes();
DatagramPacket dp3 = new DatagramPacket(sentData, sentData.length, getIP, port);
server.send(dp3);
}
}
}
The code worked when altered to localhost only.
Does anyone know what i'm doing wrong? Any replies are greatly appreciated.
Assuming the client connects to the server, the server needs to specify the port to listen and the client needs to specify IP and port of the server.
Client:
InetAddress address = InetAddress.getByName(" PUBLIC IP IS HERE");
DatagramSocket client = new DatagramSocket();
//...
DatagramPacket dp1 = new DatagramPacket(sentData, sentData.length, address, 7000);//the port should be the publicly exposed port
client.send(dp1);
This connects to the server with specified IP and port.
Server:
DatagramSocket server = new DatagramSocket(7000);//port to forward
This means that the server listens on port 7000 so it is available under that port.
Aside from that, make sure the port forwarding works correctly. If you use UDP, you also need to configure it for TCP.
Also note that UDP does neither confirm nor validate packages. If you want to have those features, you will need to either use TCP or implement those features by yourself.
When my SECOND client connect to my server I got this error:
Exception in thread "main" java.net.SocketException: Connection reset
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:200)
at java.base/java.io.DataInputStream.readLine(DataInputStream.java:518)
at Main.main(Main.java:24)
I don't know what am I doing wrong.
FIRST client works normal
My code:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class Main {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(50505);;
Socket socket;
while (true) {
socket = serverSocket.accept();
while(socket.isConnected()) {
String v;
DataInputStream in;
InputStream in_sock;
in_sock = socket.getInputStream();
in = new DataInputStream(in_sock);
v = in.readLine();
System.out.println(v);
OutputStream output = socket.getOutputStream();
DataOutputStream out = new DataOutputStream(output);
out.writeChars("123\n");
out.writeChars("123\n");
out.writeChars("123\n");
}
}
}
}
PS: How can I share error on stackoverflow? like code?
So the big issue, like some other people have said, is that your server can only accept one connection because of the lack of multi-threading.
Right now your server waits for a connection to the port specified
socket = serverSocket.accept();
Then while your socket is still connected you read a line from the socket, print it out to System.out, and then write back to the socket all in a loop. Now this comes into issue because next time a client tries to connect to your serverSocket, it can no longer accept connections because your code is stuck in a loop of reading and writing data from one Socket.
The way to fix this is to introduce multithreading in the way that Milen mentioned above.
Your code should look something like this.
public class Main {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(50505);
while (true) {
Socket socket = serverSocket.accept();
SocketHandler h = new SocketHandler(socket);
h.start();
}
}
}
public class SocketHandler extends Thread{
Socket clientSock;
public SocketHandler(Socket sock){
clientSock = sock;
}
public void run(){
while(clientSock.isConnected()) {
String v;
DataInputStream in;
InputStream in_sock;
in_sock = socket.getInputStream();
in = new DataInputStream(in_sock);
v = in.readLine();
System.out.println(v);
OutputStream output = socket.getOutputStream();
DataOutputStream out = new DataOutputStream(output);
out.writeChars("123\n");
out.writeChars("123\n");
out.writeChars("123\n");
}
}
}
Now this code has a loop that accepts connections, and spawns a new thread for every connection!
I would recommend looking at a few things. First, if you check the Java Docs for ServerSocket you will see this constructor
ServerSocket(int port, int backlog)
Creates a server socket and binds it to the specified local port number, with the specified backlog.
The backlog is the number of incoming connections the server socket can hold onto and store in some sort of buffer until they can be accepted. This is useful if a client is connecting when your accepting loop is in the middle of creating the socket handler. I would recommend putting it at the max number of clients you're expecting.
Secondly, look up the Thread class in the Javadocs. To extend Thread successfully you need to overwrite run(). This method is the method that the thread will execute with. To spawn the thread, you call ThreadObject.start(). You can think of start() as just calling run().
From the "Writing the Server Side of a Socket" tutorial from Oracle:
... the server can service them simultaneously through the use of threads—one thread per each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
The thread reads from and writes to the client connection as necessary.
In that tutorial you'll also find links to a server (KKMultiServer) and thread (KKMultiServerThread) sample implementations.
Here is use case I need to implement in Java:
Server is listening for push messages from some clients
If client has some data to push into server, it opens TCP connection and sends all messages
When client sends last message (special message saying that this is the last one) server should close connection by starting TCP closing handshake
I have problem with last step because I don't know how to close connection from server site. My current code is bellow. How to initiate connection closing TCP handshake form server site? Thank you for any help.
public class Server{
public static void main(String[] args) throws Exception {
while (true) {
int port = AppConfig.getInstance().getPort();
try (ServerSocket socket = new ServerSocket(port)) {
Socket server = socket.accept();
InetAddress ipAddress = server.getInetAddress();
MessageHandler handler = new MessageHandler(ipAddress);
InputStream in = server.getInputStream();
// reads all bytes from input stream and process them by given handler
processStream(in, handler);
in.close();
server.close();
} catch (Exception e) {
LoggingUtils.logException(e);
}
}
}
private static void processStream(InputStream in, MessageHandler handler) throws Exception {
// implementation is omitted
}
}
You've done it. in.close() closes the input stream, the socket output stream, and the socket.
What you should really close is whatever output stream was attached to the socket, to ensure it gets flushed, and you should probably do that in the processStream() method, with a saver server .close() in a finally block in the calling method.
NB Your socket names are really the wrong way round. It is customary to use ServerSocket serverSocket, and Socket socket = serverSocket.accept().
I may be not totally sure about this one, but I would believe that socket.close() will send all the commands (FIN/FIN-ACK)
I want to perform a two way communication between the client and the server and so far i have achieved one way communication.
My code in JAVA looks like,
ServerSide
public class server{
#SuppressWarnings("deprecation")
public static void main(String[] args)
{
try{
ServerSocket s=new ServerSocket(9998);
Socket ss=s.accept();
DataInputStream din=new DataInputStream(ss.getInputStream());
DataInputStream uip=new DataInputStream(System.in);
DataOutputStream dout=new DataOutputStream(ss.getOutputStream());
System.out.println("Enter message to send to client\n");
String stc=uip.readLine();
dout.writeBytes(""+stc);
din.close();
dout.close();
uip.close();
}
catch(Exception e)
{
System.out.println(e);
}`enter code here`
}
}
ClientSide
public class client{
public static void main(String[] args)
{
try{
Socket ss=new Socket("localhost",9998);
DataInputStream din=new DataInputStream(ss.getInputStream());
DataInputStream uip=new DataInputStream(System.in);
DataOutputStream dout=new DataOutputStream(ss.getOutputStream());
String msg=din.readLine();
System.out.println("Received msg is "+msg);
din.close();
dout.close();
uip.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
I tried to get input in the client side and tried to send in the same way to server. but thats not working. Where am i getting wrong? How Should i achieve a two way communication.
In the client side i got input from user and used .writeBytes(value); and performed readLine() in din in the server side as i have done above in one way communication. But that doesn't work. Where am i doing it wrong?
The best approach to create a double communication system is to create two threads one for writing messages and one to receive messages (both on client and server side).
The listening thread receive a message wake itself and do something. If a response is needed it create the response and add it to a queue.
The writing thread periodically check the queue of messages to be sent. If there are it sends them.
This is the best way for bidirectional client server communication.. "dout.shutdownOutput();" code this line after send function in client side.This is the function named as half socket closed it will helps to back and forth communication.
So I created a basic client-server program in java. It starts out like this:
Client connects to Server
Server asks for Client's name
Client responds with name
Server greets Client
After this, Client speaks and the Server repeats the words back
I got this to work without too much trouble using this tutorial. The problem comes whenever I try to introduce multiple clients. I thought that it would work because I'm using multiple threads, however, the second clients just hangs until the first client quits and then it starts it work (the server does accept input from the second client, but it doesn't respond with anything until the first client quits).
Here is the code I'm using:
import java.net.*;
import java.io.*;
public class Server extends Thread {
private ServerSocket listener;
public Server(int port) throws IOException {
listener = new ServerSocket(port);
}
public void run() {
while(true) {
try {
Socket server = listener.accept();
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("What is your name?");
DataInputStream in = new DataInputStream(server.getInputStream());
String user_name = in.readUTF();
out.writeUTF("Hello "+user_name);
while(true) {
String client_message = in.readUTF();
out.writeUTF(client_message);
}
}
catch(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int port = 6006;
try {
Thread t = new Server(port);
t.start();
} catch(IOException e) {
e.printStackTrace();
}
}
}
Can someone explain what I'm doing wrong?
I have looked at the using Runnable instead of Extends Thread, but I ran into even more problems there, so I want to try and work with this first.
Incoming connections are only handled by the line listener.accept();. But after you got a client connected, you're stuck in the while loop. You need to create a new Thread (or Runnable executed on an ExecutorService if you expect high load), and start it, then immediately accept the next connection.
In a nutshell, this is what is going wrong.
You are using exactly ONE thread as the server.
Blocking this thread when you call listener.accept()
This is what you need to do:
Create two classes
1: Server - Similar to what you have now, but instead of doing the actual work of acting as an echo server, it just spawns a new Thread which starts listening on a NEW PORT (which you can select randomly), and sends the client the address for this new port. The client will then get the new port number and would try to connect to the server on the new port.
2: The Echo thread - This starts a new listener on the port passed, and does the job of echoing to whoever is listening.
OR:
You start a UDP server rather than a TCP server, and all this will not matter then, but that is out of the purview of this specific question.