I am trying to write a program that acts as a proxy server.
Proxy server basically listens to a given port (7575) and sends the request to the server.
As of now, I did not implement caching the response.
The code looks like
ServerSocket socket = new ServerSocket(7575);
Socket clientSocket = socket.accept();
clientRequestHandler(clientSocket);
I changed the above code as below: //calling the same clientRequestHandler method from inside another method.
Socket clientSocket = socket.accept();
Thread serverThread = new Thread(new ConnectionHandler(client));
serverThread.start();
class ConnectionHandler implements Runnable {
Socket clientSocket = null;
ConnectionHandler(Socket client){
this.clientSocket = client;
}
#Override
public void run () {
try {
PrxyServer.clientRequestHandler(clientSocket);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Using the code, I am able to open a webpage like google. However, if I open another web page even I completely receive the first response, I get connection reset by peer expection.
1. How can I handle this issue
Can I use threading to handle different requests. Can someone give a reference where I look for example code that implements threading.
Related
I am building a server. I hope that after the Java server and the C# client are connected, I can send information from the HTML to the Java server, and then the Java server sends this information to the client.But I can't get the socket after the successful establishment in the service layer, so my Java server can only send fixed information to the client.
I tried using Class object = new Class(); object.setObject(socket); to save the socket, but when I call this object in the service layer, I get null;
I tried to save the socket using (Map) socket.put("socket", socket), but when I call this method in the service layer, I get null.
This is the code to make the socket. from SocketThread.java
public void run() {
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(5656);
LOGGER.info("socket server start, monitor 5656 port ! ");
Socket socket = serverSocket.accept();
new SocketClientRequest(socket).start();
LOGGER.info("send success ! ");
}catch (Exception ex){
LOGGER.error("send fail ! ");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("服务器延时重启失败 ! ");
}
}
This is a method of reading the information sent by the client using the socket and sending the information to the client. from SocketClientRequest.java
public void run() {
try {
//获取socket中的数据
bufferedInputStream = new
BufferedInputStream(socket.getInputStream());
byte[] clientCharStream = new byte[messageLengthBytes];
bufferedInputStream.read(clientCharStream);
System.out.println(new String(clientCharStream, "utf-8"));
OutputStream out = socket.getOutputStream();
out.write(new String("welcome_send_server!").getBytes());
} catch (IOException e) {
LOGGER.error("read massage error [{}]", e);
}
}
Create a connection when the project starts
#EnableScheduling
#SpringBootApplication
public class GzserverApplication {
public static void main(String[] args) {
SpringApplication.run(GzserverApplication.class, args);
SocketServer socketServer = new SocketServer();
socketServer.start();
}
}
Until this step, everything is fine, but the key problem is coming.
I need to send information to the client through my controller.
this is controller
#ResponseBody
#RequestMapping(value = "firstSend)
public SResult<String> firstSend(String uName, String pNum, String time){
try{
return httpService.firstSend(uName, pNum, time);
}catch (Exception ex){
LOGGER.error(ex.getMessage(), ex);
}
return SResult.failure("fail of connect");
}
this is service
public SResult<String> firstSend(String uName, String pNum, String time) throws Exception {
String token = TokenUtil.sign(uName);
System.out.println("token code : "+token);
SocketObject socketObject = new SocketObject();
Map<String, Socket> socketMap = socketObject.socket();
Socket socket1 = socketMap.get("Socket"); // is null
Socket socket2 = socketObject.getSocket(); // is null
return SResult.success(token);
}
I hope that after the connection is successfully created, the socket can be used in the service layer, and the information is sent to the client through the socket, but no matter what I do, the socket is null in the service layer.please give me a help, thank you very much
You should not be dealing with Sockets if using Spring. Spring is a very extensive abstraction layer, that lets you avoid having to deal with the nasty details that Sockets introduce.
In your controller, you call: SocketObject socketObject = new SocketObject(); This creates a new object, presumably with a null-initialized Socket object. Nowhere in this code do you pass a socket object from the main() scope to any other scope (for example using a method named setSocket(Socket socket).
However, and I cannot stress this enough, you should not use Sockets in Spring. Think about what problem you are trying to solve, and ask yourself (why do I need to send information to the client). It is likely that Spring has a module that will do this for you in a much more scalable and manageable way.
For example, perhaps you need to establish 2-way communication between the server and the client, and need to post information to the client periodically. In this case, the WebSocket protocol (and associated Spring Websocket library) might be for you.
This is likely an XY problem. If you edit your question to illustrate the functionality you are trying to implement, it may be easier to help
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)
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.
I have two java applications, one is web app and another is simple java app, So I am using Socket programming for communication between them.
I made one SocketServer which is a Thread, in which I created ServerSocket serverSocket = new ServerSocket(6789)
And in my web app I created Socket client = new Socket("localhost", 6789);
My server sends some data to client and client will start some other work, but if I want to run another client i.e. server will send different parameters and client have to start processing what should I do?
Because server is already started on '6789' port and first client also with the same port. How can I start client with another port?
Every time Server must have to started first and then client.
I think client will not found server till both are having same ports.
Am I have to create another server instance with different port and then invoke client??? But How can my client will know on which port server is started?
For Example:
Imagine I have UI like:
start MIlind
start xyz
start abc
and click on strart it will call client and start process, If an start Milind first then How will I start xyz?
because 'start Milind' started client and server at port 6789, How will other start process works?
It seems like a lot of overhead to create a server/client app just for a web app to communicate with a local java program (and even more so to duplicate this process to do more than one thing at a time). If you are looking for concurrent processing in the background of a web app, you can always just create a thread (or multiple threads) to do the work. Or is there a reason why the simple java app can't be embedded in the web app?
You need to split off threads when accepting your socket connections server side. This is very easily done with serversocket. A very rudimentary (untested!) implementation:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
class Server {
private ServerSocket socket;
public Server() {
try {
this.socket = new ServerSocket(6789);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void go() throws IOException {
while(true) {
Socket sock = socket.accept();
new Thread(new ClientSession(sock)).start();
}
}
public static void main(String[] args) {
Server server = new Server();
try {
server.go();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class ClientSession implements Runnable {
private final Socket clientsocket;
ClientSession(Socket sock) {
this.clientsocket = sock;
}
#Override
public void run() {
//do stuff, like read from socket.
}
}
}
Note that you don't need to change the port at all.