자바, 소켓

2023. 3. 28. 10:19Lang/Java

728x90
반응형

1. 소켓 프로그래밍

  • 소켓을 이용한 통신 프로그래밍
  • 클라이언트와 서버간의 일대일 통신
  • 소켓 : 프로세스간 통신에 사용되는 양쪽 끝단을 의미
  • java.net 패키지 이용

통신방식

  • TCP 통신방식
    • 양방향 연결 기반 통신방식 (Connection Oriented)
    • 신뢰성 있는 데이터 전송 (수신여부 확인)
    • 연결 후 통신
    • 데이터 손실 시 재전송
  • UDP 통신방식
    • 비연결 기반 통신 방식
    • 신뢰성 없는 데이터 전송 (수신여부 미확인)
    • 연결 없이 통신
    • 데이터가 손실될 수 있다
    • 전송속도가 빠르다

캡처

2. TCP 소켓 프로그래밍

  • 클라이언트와 서버 간 일대일 통신
  • 먼저 프로그램이 실행되어 클라이언트 프로그램의 연결요청을 기다려야 한다
  • 통신과정
    • 서버프로그램 : 서버소켓을 사용, 특정 포트에서 클라이언트의 연결 요청을 처리할 준비
    • 클라이언트프로그램 : 접속할 서버의 IP주소와 포트정보를 가지고 소켓 생성, 서버에 연결 요청
    • 서버소켓 : 연결요청을 받으면 서버에 새로운 소켓을 생성, 클라이언트의 소켓과 연결
  • 서버소켓
    • 포트와 결합되어 포트를 통해 사용자의 연결요청을 대기
    • 연결 요청이 올때마다 새로운 소켓을 생성, 상대편 소켓과 연결
    • 실질 데이터통신은 서버소켓과 관계없이, 새로 생성된 소켓과 클라이언트 소켓간에 이루어진다
  • 포트
    • 컴퓨터가 외부와 통신을 하기 위한 통로
    • 하나의 호스트(컴퓨터)가 65,536개의 포트를 소유
    • 0~1024 사이 값은 시스템이 사용하는 포트번호
  • 소켓은 입력스트림과 출력스트림 보유
    • 상대 소켓의 스트림과 교차연결

서버소켓 생성

package com.nw.day1;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer1 {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        DataOutputStream dos = null;


        try {
            //서버소켓을 생성하여 7777번 포트와 결합(bind)
            serverSocket = new ServerSocket(7777);
            //ServerSocket(int port)


            System.out.println(MyUtil.getTime()+"서버 준비 완료");
        } catch (IOException e) {
            e.printStackTrace();
        }


        while(true) {
            System.out.println(MyUtil.getTime()+"연결요청 대기");
            //서버소켓은 클라이언트의 연결요청이 올때까지 실행을 멈추고 기다린다
            //클라이언트의 연결요청이 오면 클라이언트 소켓과 통신할 새로운 소켓을 생성한다

            try {
                socket = serverSocket.accept();
                System.out.println(MyUtil.getTime()+socket.getInetAddress()+"로부터 연결요청");


                //소켓의 출력스트림
                OutputStream os = socket.getOutputStream();
                dos = new DataOutputStream(os);

                //원격 소켓에 데이터를 보낸다
                dos.writeUTF("서버가 데이터 전송");
                System.out.println(MyUtil.getTime()+"데이터 전송");

            }catch(IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if(dos!=null) dos.close();
                    if(socket!=null) socket.close();
                }catch(IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

클라이언트 소켓 생성

package com.nw.day1;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class TcpClient1 {

    public static void main(String[] args) {
        String serverIp = "192.168.0.66";
        System.out.println("서버에 연결중입니다. 서버 ip : "+serverIp);

        Socket socket = null;
        DataInputStream dis = null;

        try {
            //소켓을 생성하여 연결 요청
            //Socket(String host, int port)
             socket = new Socket(serverIp, 7777);

            //소켓의 입력스트림을 얻는다
            InputStream is = socket.getInputStream();
             dis = new DataInputStream(is);

            //소켓으로부터 받은 데이터를 출력한다
            System.out.println("서버로부터 받은 메시지 : "+dis.readUTF());
            System.out.println("연결종료");
        }catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(dis!=null) dis.close();
                if(socket!=null) socket.close();
                System.out.println("연결종료 완료");
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }
}

결과

/* 
- 서버
[12:33:06]서버 준비 완료
[12:33:06]연결요청 대기
[12:34:32]/192.168.0.66로부터 연결요청
[12:34:32]데이터 전송
[12:34:32]연결요청 대기

- 클라이언트
서버에 연결중입니다. 서버 ip : 192.168.0.66
서버로부터 받은 메시지 : 서버가 데이터 전송
연결종료
연결종료 완료
*/

채팅

서버

package com.nw.day1;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class TcpGuiServer extends JFrame implements ActionListener {

    JTextArea taList;
    JScrollPane scrollPane;
    JTextField tfChat;
    JButton btSend;
    JPanel pl;

    //Socket socket;
    DataOutputStream dos;
    String name;

    public TcpGuiServer() {
        super("[Server]");

        taList = new JTextArea();
        taList.setEditable(false);

        scrollPane = new JScrollPane(taList);
        pl=new JPanel(new BorderLayout());
        tfChat = new JTextField();
        btSend = new JButton("전송");
        pl.add(btSend,"East");
        pl.add(tfChat,"Center");

        add(scrollPane, "Center");
        add(pl,"South");

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(300, 400);

        tfChat.addActionListener(this);
        btSend.addActionListener(this);
    }

    public static void main(String[] args) {
        TcpGuiServer f = new TcpGuiServer();
        f.setVisible(true);
        f.startMain();

    }

    private void startMain() {
        System.out.println("[=======server======]\n\n");

        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println(MyUtil.getTime()+"서버 준비 완료 \n");

            //클라이언트에서 요청 들어오면 쓰레드 생성
            System.out.println("연결요청 기다림");
            Socket socket = serverSocket.accept();
            System.out.println(socket.getInetAddress()+", "+socket.getPort()+"에서 연결요청 들어옴");

            name = "Server";

            //출력용 스트림
            dos = new DataOutputStream(socket.getOutputStream());

            //쓰레드 실행
            ServerReceiver th = new ServerReceiver(socket);
            th.start();
        }catch(IOException e) {
            e.printStackTrace();
        }
    }

    class ServerReceiver extends Thread{
        Socket socket;
        DataInputStream dis;

        public ServerReceiver(Socket socket) {
            this.socket = socket;

            //입력용 스트림
            try {
                dis = new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        public void run() {
                try {
                    while(dis!=null) {
                        String data = dis.readUTF();
                        taList.append(data+"\n");
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==btSend || e.getSource()==tfChat) {
            try {
                if(dos!= null) {
                    dos.writeUTF("["+name + "] " + tfChat.getText()+ "\n");
                    tfChat.setText("");
                    tfChat.requestFocus();
                }
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

    }

}

클라이언트

package com.nw.day1;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class TcpGuiClient extends JFrame implements ActionListener {

    JTextArea taList;
    JScrollPane scrollPane;
    JTextField tfChat;
    JButton btSend;
    JPanel pl;

    //Socket socket;
    DataOutputStream dos;
    String name;


    public TcpGuiClient(){
        super("[Client");

        taList = new JTextArea();
        taList.setEditable(false);

        scrollPane = new JScrollPane(taList);
        pl=new JPanel(new BorderLayout());
        tfChat = new JTextField();
        btSend = new JButton("전송");
        pl.add(btSend,"East");
        pl.add(tfChat,"Center");

        add(scrollPane, "Center");
        add(pl,"South");

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(300, 400);

        tfChat.addActionListener(this);
        btSend.addActionListener(this);
    }

    public static void main(String[] args) {
        TcpGuiClient f = new TcpGuiClient();
        f.setVisible(true);
        f.startMain();

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==btSend || e.getSource()==tfChat) {
                try {
                    if(dos!=null) {
                        dos.writeUTF("["+name+"]"+tfChat.getText()+"\n");
                        tfChat.setText("");
                        tfChat.requestFocus();
                    }
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
        }

    }
    public void startMain() {
        name = JOptionPane.showInputDialog(this, "닉네임 입력");
        this.setTitle("[client -"+name+"]");

        try {
            Socket socket = new Socket("192.168.0.66",8888);
            taList.append(MyUtil.getTime()+"서버에 연결됨");

            dos = new DataOutputStream(socket.getOutputStream());

            //입력용 쓰레드 실행
            ClientReceiver th = new ClientReceiver(socket);
            th.start();
        }catch (IOException e) {

        }
    }
    class ClientReceiver extends Thread{
        Socket socket;
        DataInputStream dis;
        public ClientReceiver(Socket socket) {
            this.socket = socket;
            try {
                //입력용 스트림
                dis = new DataInputStream(socket.getInputStream());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        public void run() {
            while(dis!=null) {
                String data;
                try {
                    data = dis.readUTF();
                    taList.append(data+"\n");
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

}

3. UDP 소켓프로그래밍

  • TCP에서는 Socket과 ServerSocket 사용
  • UDP에서는 DatagramSocket과 DatagramPacket을 사용
  • 연결요청을 받아줄 서버소켓이 필요 없다
  • DatagramPacket을 주고받는다

클라이언트

package com.nw.day1;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class UDPClient {

    public static void main(String[] args) {
        /*
         * 데이터 그램 소켓 생성 후 소켓 객체의 send() 메서드에
         * 데이터 그램 패킷 객체를 매개변수로 넣어서 전송
         */

        int port = 3000;
        try {
            InetAddress inet = InetAddress.getByName("192.168.0.66");

            Scanner sc= new Scanner(System.in);
            String msg = "";
            System.out.println("보낼 내용 입력:");
            DatagramPacket packet = null;
            DatagramSocket socket = new DatagramSocket();

            while((msg=sc.nextLine())!=null) {
                if(msg.equalsIgnoreCase("x")) break;

                byte[] data = msg.getBytes();
                packet = new DatagramPacket(data,data.length,inet,port);
                socket.send(packet);
                System.out.println("보낼내용 입력:");
            }

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

서버

package com.nw.day1;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPServer {

    public static void main(String[] args) {
        byte[] buffer = new byte[100];
        //클라이언트가 보낸 데이터를 담아줄 바이트 배열 생성


        try {
            DatagramSocket socket = new DatagramSocket(3000);
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

            while(true) {
                //datagramsocket의 receive()메서드를 이용하여 패킷을 받는다
                socket.receive(packet);

                byte bmsg[] = packet.getData();
                //버퍼배열에 담긴 데이터를 문자열로 만들어 출력
                String msg = new String(bmsg, 0, packet.getLength());
                //String(byte[] bytes, int offset, int length)

                System.out.println(packet.getAddress()+"로부터 "+packet.getPort()+"번 포트에서 온 메세지:"+msg);
            }
        }catch(SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
728x90
반응형

'Lang > Java' 카테고리의 다른 글

자바, 네트워크  (0) 2023.03.28
쓰레드의 동기화  (0) 2023.03.28
자바에서의 입출력, I/O  (0) 2023.03.28
Swing, Jtable  (1) 2023.03.28
AWT - 이벤트처리  (0) 2023.03.28