Home >Java >javaTutorial >Memo for beginners to learn Java (6)
After establishing the actual concept through the program, we should now return to the original question, what is Socket? It is a way to achieve computer communication, there is no doubt about it. But how can we use the easiest to understand language to compare the image and yet How about an unbiased description of its principle?
BrUCe Eckel describes sockets in his book "Java Programming Thoughts":
A socket is a software abstraction used to express the connection between two machines "terminal". For a given connection, there is a socket on each machine, or you can imagine a virtual "cable" between them, with each end of the "cable" plugged into a socket. Of course, the physical hardware and cabling between the machines are completely unknown. The whole purpose of abstraction is to prevent us from knowing the details that we don’t need to know.
According to my understanding, from an abstract point of view, a Socket is a telephone receiver. You have one, and the person you are talking to also has one, but there is only one person in it. The receiver of one person is called ServerSocket, and the receiver of another person is called Socket. As for who is ServerSocket and who is Socket, it does not matter, because the client and server are inherently relative and can be converted into each other. The two people talking can pick up the two A channel is established with two receivers. Whether this channel is open depends on whether both parties have picked up the receiver. If only one party picks up the receiver, you will only hear some beeping sounds, confirming that the channels are different. Here, take The process of picking up the receiver is the process of Socket initialization. After the channel is established, that is, after everyone picks up the receiver, people at both ends of the channel can start talking. There are two processes here, namely A talks to B and B answers. B talks to A, and A listens. These two processes are completed through two lines. What is transmitted on these two lines is the stream. The stream hides all the details of the transmission, making both communicating parties think that they have transmitted it. It's the sound, not the encoding.
The server-side program written earlier is actually a single-task version. The server's processing mechanism for the client is that it can only process one connection in the same time period, because the handleConnection adopts a continuous loop. The blocking method is to detect one, process it, and then detect another one, process another one. If there are multiple connections requesting at the same time, you can only wait in line. Such a program cannot cope with multiple connections in the network. , because you cannot guarantee that only one client will make a connection request to the server at the same time, and the speed of using a blocking method to deal with multiple client connections is conceivably slow.
This gave birth to a multi-connection oriented version .Obviously, our requirements can be achieved through multi-threading.
Since the problem to be solved is to deal with client connections, our work is only to modify the server-side program. The principle is not difficult to deduce, that is, when a connection is detected After the request, a thread is immediately created to process it, and then continues to listen to the next connection request. Therefore, we only need to put the original code in handleConnection intact into the execution code of the thread, and add in handleConnection Just create the code for the new thread, it’s very simple.
The same style as the previous article, let’s observe the code details of each part.
First create the class MultiThreadRemoteFileServer for this multi-threaded version
Look at the definition of this class
import java.io.*;
import java.net.*;
public class MultiThreadRemoteFileServer{
PRotected int listenPort;
public MultiThreadRemoteFileServer(int aListenPort){
}
public static void main(String[] args) {
}
public void acceptConnections() {
}
public void handleConnection(Socket incomingConnection) {
}
}
is almost the same as RemoteFileServer. The only difference is that a constructor has been added to the class we created now, which is In order to enable the listening port number to be determined by ourselves, the definition is as follows
public MultithreadedRemoteFileServer(int aListenPort) {
listenPort = aListenPort;
}
Let’s first look at main()
public static void main(String[] args) {
MultithreadedRemoteFileServer server = new MultithreadedRemoteFileServer(3000);
server.acceptConnections();
}
There is no difference, it is the same as the main() function of RemoteFileServer, but the port number is specified by the main program when it is created.
The changes we are mainly concerned about are at the back
Now look at the acceptConnection listener program
public void acceptConnections() {
try {
ServerSocket server = new ServerSocket(listenPort, 5);//Notice that there is a lot of time to create a server Socket A parameter is used to specify the maximum number of connections that can be applied for at the same time. The default value is 50
Socket incomingConnection = null;
while (true) {
incomingConnection = server.accept();
handleConnection(incomingConnection);
}
} catch (BindException e) {
System.out.println("Unable to bind to port " + listenPort);
} catch (IOException e) {
System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
}
}
The only change is one more parameter. Here is its working mechanism. Suppose we specify that the backlog value is 5 and there are five clients requesting connections to our server. Our server will start processing the first connection, but it will take a long time to process that connection. Since our pending value is 5, we can put five requests in the queue at a time. We're working on one, so that means there are five others waiting. There are six in total waiting and being processed. When our server is still busy accepting connection No. 1 (remember there are still No. 2~6 in the queue), if a seventh client makes a connection request, then the seventh client will be rejected
Then Look, our next change is obviously in the method handleConnection that handles the monitored thread. As mentioned before, in the multi-threaded version, when we detect a connection request, we immediately generate a thread and then ignore it. , then here is a sentence to create a new thread.
public void handleConnection(Socket connectionToHandle) {
new Thread(new ConnectionHandler(connectionToHandle)).start();
}
We noticed that there is a new class ConnectionHandler , this class is Runnable, that is, an interface class (this is a thread implemented using an interface. If you don’t understand, you can read about threads on No. 17). We use ConnectionHandler to create a new Thread and start it. it. As we just said, the original code in the handleConnection of RemoteFileServer has been transferred intact to the run() method of this interface class ConnectionHandler.
Then let’s take a look at the definition of the entire ConnectionHandler class.
class ConnectionHandler implements Runnable {
protected Socket socketToHandle;
public ConnectionHandler(Socket aSocketToHandle) {
socketToHandle = aSocketToHandle;//Through the constructor, pass in the Socket instance to be processed as a parameter
}
public void run() { //The original code for reading/writing Socket is all here
try {
PrintWriter streamWriter = new PrintWriter(socketToHandle.getOutputStream());
BufferedReader streamReader = new BufferedReader(new InputStreamReader(socketToHandle.getInputStream()));
String fileToRead = streamReader.readLine();
BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));
String line = null;
while ((line = fileReader.readLine()) != null)
streamWriter .println(line);
fileReader.close();
streamWriter.close();
streamReader.close();
} catch (Exception e) {
System.out.println("Error handling a client: " + e);
}
}
}
ConnectionHandler's run() method does what handleConnection() on RemoteFileServer does. First, wrap InputStream and OutputStream (using Socket's getOutputStream() and getInputStream()) into BufferedReader and PrintWriter respectively. Then we use these codes to read the target file line by line. Since the file path is loaded in the InputStream, we need to use the FileReader stream to wrap the file path in the middle, and then read it out through the BufferedReader package.
We have finished researching the multi-threaded server. Again, let's review the steps for creating and using a "multi-threaded version" of a server:
1. Modify acceptConnections() to instantiate a ServerSocket with the default of 50 (or any specified number you want greater than 1).
2. Modify ServerSocket's handleConnection() to generate a new Thread with an instance of ConnectionHandler.
3. Borrow the code of the handleConnection() method of RemoteFileServer to implement the run() function of the ConnectionHandler class.
The above is the content of the memo (6) for beginners learning Java. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!