촬리의늘솔길

java socket 통신 스레드 이해하기 본문

✍~2022/java

java socket 통신 스레드 이해하기

리촬리 2022. 6. 1. 02:40

네트워크 프로그래밍에서 스레드를 이용하는 이유는?

->

여러 클라이언트를 동시에 연결하는것이 좋다.

클라이언트 요청이 수신될 때마다, 각 요청을 처리하기 위해 별도의 스레드를 할당할 수 있도록 서버측에서 스레드를 사용해야한다.

 

creating a Simple Date-Time server for handling multiple client requests at the same time.

Server.java 와 Client.java 라는 2개의 java 파일을 만든다.

서버 파일에는 Server(서버를 작성하기 위한 public class)와 

ClientHandler(멀티 스레딩을 사용하여 클라이언트를 처리하기 위한 클래스) 2개의 클래스가 있다.

클라이언트 파일에는 클라이언트를 작성하기 위한 퍼블릭 클래스 클라이언트가 1개만 포함되어있다.

이들 3개의 클래스가 어떻게 상호작용 하는지

서버측 프로그래밍

더보기

Server class :

// A Java program for a Server
import java.net.*;
import java.io.*;
 
public class Server
{
    //initialize socket and input stream
    private Socket          socket   = null;
    private ServerSocket    server   = null;
    private DataInputStream in       =  null;
 
    // constructor with port
    public Server(int port)
    {
        // starts server and waits for a connection
        try
        {
            server = new ServerSocket(port);
            System.out.println("Server started");
 
            System.out.println("Waiting for a client ...");
 
            socket = server.accept();
            System.out.println("Client accepted");
 
            // takes input from the client socket
            in = new DataInputStream(
                new BufferedInputStream(socket.getInputStream()));
 
            String line = "";
 
            // reads message from client until "Over" is sent
            while (!line.equals("Over"))
            {
                try
                {
                    line = in.readUTF();
                    System.out.println(line);
 
                }
                catch(IOException i)
                {
                    System.out.println(i);
                }
            }
            System.out.println("Closing connection");
 
            // close connection
            socket.close();
            in.close();
        }
        catch(IOException i)
        {
            System.out.println(i);
        }
    }
 
    public static void main(String args[])
    {
        Server server = new Server(5000);
    }
}

1.Establishing the Connection: 서버 오브젝트가 초기화되어서 while loop내에서는 소켓 오브젝트가 계속 접속을 받아들인다.

2. Obtaning the Streams : 입력 스트림 개체 및 출력스트림 개체가 현재 요청의 소켓 개체에서 추출된다.

3. Creating a handler object : 스트림과 포트번호를 취득한 후 이들 파라미터를 사용하여 새로운 client handler 오브젝트가 생성된다.

4. invoking the start() : start ()메소드는 새로 생성된 스레드 오브젝트에서 호출한다.

 

https://qh5944.tistory.com/37

https://iancoding.tistory.com/41

https://github.com/1ilsang/java-mvc-chatting/blob/master/markdown/index/Server.md

https://github.com/1ilsang/java-mvc-chatting/blob/master/server/ChatServer.java

https://papago.naver.net/website?locale=ko&source=en&target=ko&url=https%3A%2F%2Fwww.geeksforgeeks.org%2Fmulti-threaded-chat-application-set-1%2F 


1. 서버는 무한루프를 실행하여 착신 요구 받아들임

2. 요청이 오면 통신부분 처리 위해서 새 스레드 할당

3. 서버는 접속된 디바이스를 추적하기 위해 클라이언트 이름도 벡터에 저장함. 벡터는 현재 요구에 대응하는 스레드 객체를 저장함. 도우미 클래스는 이 벡터를 사용하여 메시지 전달처의 수신인 이름을 검색함. 벡터는 모든 스트림을 보유하고있기 때문에 핸들러 클래스는 이 벡터를 사용하여 메시지를 특정 클라이언트에 정상적으로 전달할 수 있음.

4.start()메서드 호출

// Java implementation of  Server side
// It contains two classes : Server and ClientHandler
// Save file as Server.java
 
import java.io.*;
import java.util.*;
import java.net.*;
 
// Server class
public class Server
{
 
    // Vector to store active clients
    static Vector<ClientHandler> ar = new Vector<>();
     
    // counter for clients
    static int i = 0;
 
    public static void main(String[] args) throws IOException
    {
        // server is listening on port 1234
        ServerSocket ss = new ServerSocket(1234);
         
        Socket s;
         
        // running infinite loop for getting
        // client request
        while (true)
        {
            // Accept the incoming request
            s = ss.accept();
 
            System.out.println("New client request received : " + s);
             
            // obtain input and output streams
            DataInputStream dis = new DataInputStream(s.getInputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
             
            System.out.println("Creating a new handler for this client...");
 
            // Create a new handler object for handling this request.
            ClientHandler mtch = new ClientHandler(s,"client " + i, dis, dos);
 
            // Create a new Thread with this object.
            Thread t = new Thread(mtch);
             
            System.out.println("Adding this client to active client list");
 
            // add this client to active clients list
            ar.add(mtch);
 
            // start the thread.
            t.start();
 
            // increment i for new client.
            // i is used for naming only, and can be replaced
            // by any naming scheme
            i++;
 
        }
    }
}
 
// ClientHandler class
class ClientHandler implements Runnable
{
    Scanner scn = new Scanner(System.in);
    private String name;
    final DataInputStream dis;
    final DataOutputStream dos;
    Socket s;
    boolean isloggedin;
     
    // constructor
    public ClientHandler(Socket s, String name,
                            DataInputStream dis, DataOutputStream dos) {
        this.dis = dis;
        this.dos = dos;
        this.name = name;
        this.s = s;
        this.isloggedin=true;
    }
 
    @Override
    public void run() {
 
        String received;
        while (true)
        {
            try
            {
                // receive the string
                received = dis.readUTF();
                 
                System.out.println(received);
                 
                if(received.equals("logout")){
                    this.isloggedin=false;
                    this.s.close();
                    break;
                }
                 
                // break the string into message and recipient part
                StringTokenizer st = new StringTokenizer(received, "#");
                String MsgToSend = st.nextToken();
                String recipient = st.nextToken();
 
                // search for the recipient in the connected devices list.
                // ar is the vector storing client of active users
                for (ClientHandler mc : Server.ar)
                {
                    // if the recipient is found, write on its
                    // output stream
                    if (mc.name.equals(recipient) && mc.isloggedin==true)
                    {
                        mc.dos.writeUTF(this.name+" : "+MsgToSend);
                        break;
                    }
                }
            } catch (IOException e) {
                 
                e.printStackTrace();
            }
             
        }
        try
        {
            // closing resources
            this.dis.close();
            this.dos.close();
             
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

위의 프로그램에서 명확하게 관찰할 수 있는 은 클라이언트 수가 많아지면 핸들러 클래스에서 검색 시간이 증가한다는 것입니다.

이 증가를 피하기 위해 2개의 해시 맵을 사용할 수 있습니다.

이름이 키로 지정되고 활성 목록의 인덱스가 값으로 지정됩니다.

인덱스를 키로 하고 관련 핸들러 개체를 값으로 하는 다른 개체.이렇게 하면 2개의 해시맵을 검색하여 수신자와 일치시킬 수 있습니다.

 

일단 여기까지..

내일부터는 코드를 짜보자..!

728x90

'✍~2022 > java' 카테고리의 다른 글

객체 지향 개념  (0) 2022.08.03
java 강의  (0) 2022.08.02
spring부트와 aws로 구현하는 웹서비스 따라하기(1)  (0) 2022.07.29
java 에서의 소켓 프로그래밍[서버]  (0) 2022.06.01
학교 객프 수업 필기(1주차)  (0) 2021.09.03