네트워크 통신

from JAVA 2013. 6. 7. 14:43

스레드, TCP/IP를 중점적으로 공부

네트워크에서 소켓이라 함은 일반적으로 "연결"시키기 위한것.

연결은 보통 이런 절차를 거침 : 소켓 클래스를 통해 IP를 찾고, 그 다음 포트를 찾는다.

 

서버소켓에 사용할때는 포트번호만 쓰면 된다. IP필요없다. 클라이언트가 서버를 찾아오지 서버가 클라를 찾지X

서버는 항상 클라이언트보다 먼저 동작하고 있어야만 반응을 하겠지?

 

-서버가 '헬로 클라이언트'라고 보내주면 클라이언트가 '헬로 서버'라고 하는 프로그램

서버에서 먼저 실행을 하면 리스닝 모드(대기 모드)가 된다. 이때 클라이언트에서 실행해주면 비로서 두개가 실행됨.

그리고 서버와 클라이언트는 서로 포트를 맞춰야 함

//서버 

import java.io.*;

import java.net.*;

class ServerExample1 

{

 public static void main(String[] args) 

 {

  ServerSocket serverSocket=null;

  Socket socket = null;

  try{

   serverSocket = new ServerSocket(9000);//서버는 기본이 패스브 모드이므로 포트만 열어주면 ok!

   socket = serverSocket.accept();

   InputStream in = socket.getInputStream(); //받아오는 스트림

   OutputStream out = socket.getOutputStream(); //보내는 스트림

   byte arr[] = new byte[100];

   in.read(arr); //받아왔으니 읽어야지.

   System.out.println(new String(arr));//읽었으니 출력해야지.

   String str = "Hello, Client";

   out.write(str.getBytes());  //이번에는 내가(서버)가 문자열을 보낸다!

   

  }

  catch(Exception e){

   System.out.println(e.getMessage());

  }

  finally{

   try{

    socket.close();

   }

   catch(Exception ignored){

   }

  }

 }

}

//클라이언트 

import java.io.*;
import java.net.*;
class ClientExample1
{
 public static void main(String[] args)
 {
  Socket socket = null;
  try{
   socket = new Socket("210.99.86.106",9000); //서버의 주소와 포트
   InputStream in = socket.getInputStream();
   OutputStream out = socket.getOutputStream();
   String str = "Hello. Server";
   out.write(str.getBytes());
   byte arr[] = new byte[100]; //버퍼 한계
   in.read(arr);
   System.out.println(new String(arr));
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
  finally{
   try{
    socket.close();
   }
   catch(Exception e){}
  }
 }
}

 

스트림으로 처리??

import java.io.*;
import java.net.*;
class ClientExample2
{
 public static void main(String[] args)
 {
  Socket socket=null;
  try{
   socket = new Socket("210.99.86.106",9000);
   BufferedReader reader = new BufferedReader(
    new InputStreamReader(socket.getInputStream()));
   PrintWriter writer = new PrintWriter(socket.getOutputStream());
   writer.println("헬로우 병래's Server? 난 경석's Client");
   writer.flush();
   String str = reader.readLine();
   System.out.println(str);
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
  finally{
   try{
    socket.close();
   }
   catch(Exception ignored){
   }
  }
 }
}

 

퍼포먼스를 위해 스레드 처리로 통신

스레드 처리를 하면 동시에 처리가 되므로 이 프로그램을 실행하면 1:1 채팅방이 실행된다^0^

//클라이언트

import java.net.*;
class ClientExample3 //스레드처리
{
 public static void main(String[] args)
 {
  Socket socket = null;
  try{
   socket = new Socket("210.99.86.106",9000);
   Thread thread1 = new SenderThread(socket);
   Thread thread2 = new ReceiverThread(socket);
   thread1.start();
   thread2.start();
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
 }
}

//서버

import java.net.*;
class ServerExample3
{
 public static void main(String[] args)
 {
  ServerSocket serverSocket = null;
  Socket socket = null;
  try{
   serverSocket = new ServerSocket(9000);
   socket = serverSocket.accept();
   Thread thread1 = new SenderThread(socket);
   Thread thread2 = new ReceiverThread(socket);
   thread1.start();
   thread2.start();
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
  finally{
   try{
    serverSocket.close();
   }
   catch(Exception igonred){};
  }
 }
}

import java.io.*;
import java.net.*;
class SenderThread extends Thread
{
 Socket socket;
 SenderThread(Socket socket){
  this.socket = socket;
 }
 public void run(){
  try{
   BufferedReader reader = new BufferedReader(
    new InputStreamReader(System.in));
   PrintWriter writer = new PrintWriter(socket.getOutputStream());
   while(true){
    String str = reader.readLine();
    if(str.equals("bye")) break;
    writer.println(str);
    writer.flush();
   }
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
  finally{
   try{
    socket.close();
   }
   catch(Exception ignored){
   }
  }
 }
}

import java.io.*;
import java.net.*;
class ReceiverThread extends Thread
{
 Socket socket;
 ReceiverThread(Socket socket){
  this.socket = socket;
 }
 public void run(){
  try{
   BufferedReader reader = new BufferedReader(
    new InputStreamReader(socket.getInputStream()));
   while(true){
    String str = reader.readLine();
    if(str==null) break;
    System.out.println("수신>" + str);
   }
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
 }
}

 

서버에다 메세지를 보내고 메세지 보낸이, 받는이 전체에게 브로드캐스팅하는 방식으로 멀티 채팅 프로그램을 만들 수 있다.

//서버

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class MultiChatServer {

 // 서버 소켓과 클라이언트 연결 소켓
 private ServerSocket ss = null;
 private Socket s = null;
 
 // 연결된 클라이언트 스레드를 관리하는 ArrayList
 ArrayList <ChatThread> chatlist = new ArrayList <ChatThread>();
 
 // 멀티챗 메인 프로그램부
 public void start() {
  try {
   // 서버 소켓 생성
   ss = new ServerSocket(8888);
   System.out.println("server start");
   
   // 무한루프를 돌면서 클라이언트 연결을 기다림
   while(true) {
    s = ss.accept();    
    // 연결된 클라이언트에서 스레드 클래스 생성
    ChatThread chat = new ChatThread();
    // 클라이언트 리스트 추가
    chatlist.add(chat);
    // 스레드 시작
    chat.start();
   }
  } catch(Exception e) {
   // System.out.println(e);
   System.out.println("[MultiChatServer]start() Exception 발생!!");
  }  
 }
 
 public static void main(String[] args) {
  MultiChatServer server = new MultiChatServer();
  server.start();
 }
 
 // 연결된 모든 클라이언트에 메시지 중계
 void msgSendAll(String msg) {
  for(ChatThread ct : chatlist) {
   ct.outMsg.println(msg);
  }
 }

 // 각 클라이언트 관리를 위한 스레드 클래스
 class ChatThread extends Thread {
  
  // 수신 메시지와 파싱 메시지 처리하는 변수 선언
  String msg;
  String[] rmsg;
  
  // 입출력 스트림 생성
  private BufferedReader inMsg = null;
  private PrintWriter outMsg = null;

  public void run() {
  
   boolean status = true;
   System.out.println("##ChatThread start...");
   try {
    // 입출력 스트림 생성
    inMsg = new BufferedReader(new InputStreamReader(s.getInputStream()));
    outMsg = new PrintWriter(s.getOutputStream(), true);
    
    // 상태정보가 true면 루프를 돌면서 사용자한테서 수신된 메시지 처리
    while(status) {
     // 수신된 메시지를 msg 변수에 저장
     msg = inMsg.readLine();
     // '/' 구분자를 기준으로 메시지를 문자열 배열로 파싱
     rmsg = msg.split("/");
     
     // 파싱된 문자열 배열의 두번째 요소값에 따라 처리
     // 로그아웃 메시지일 때
     if(rmsg[1].equals("logout")) {
      chatlist.remove(this);
      msgSendAll("server/" + rmsg[0] + "님이 종료했습니다.");
      // 해당 클라이언트 스레드 종료로 인해 status를 false로 설정
      status = false;
     }
     // 로그인 메시지일 때
     else if(rmsg[1].equals("login")) {
      msgSendAll("server/"+rmsg[0]+"님이 로그인했습니다.");
     }
     // 그 밖의 일반 메시지일 때
     else {
      msgSendAll(msg);
     }
    } // while 종료
    // 루프를 벗어나면 클라이언트 연결이 종료되므로 스레드 인터럽트됨
    this.interrupt();
    System.out.println("##"+this.getName()+"stop!!");
   } catch(IOException e) {
    chatlist.remove(this);
    // e.printStackTrace();
    System.out.println("[ChatThread]run() IOException 발생!!");
   }
  }
 }
 
}

//클라이언트


import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

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

public class MultiChatClient implements ActionListener, Runnable {
    private String ip;
    private String id;
    private Socket socket;
    private BufferedReader inMsg = null;
    private PrintWriter outMsg = null;

    // 로그인 패널
    private JPanel loginPanel;
    // 로그인 버튼
    private JButton loginButton;
    // 대화명 라벨
    private JLabel label1;
    // 대화명 입력 텍스트 필드
    private JTextField idInput;

    // 로그아웃 패널 구성
    private JPanel logoutPanel;
    // 대화명 출력 라벨
    private JLabel label2;
    // 로그아웃 버튼
    private JButton logoutButton;

    // 입력 패널 구성
    private JPanel msgPanel;
    // 메시지 입력 텍스트 필드
    private JTextField msgInput;
    // 종료 버튼
    private JButton exitButton;

    // 메인 윈도우
    private JFrame jframe;
    // 채팅 내용 출력 창
    private JTextArea msgOut;

    // 카드 레이아웃 관련
    private Container tab;
    private CardLayout clayout;
    private Thread thread;

    // 상태 플래그
    boolean status;

    public MultiChatClient(String ip) {
        this.ip = ip;

        // 로그인 패널 구성
        loginPanel = new JPanel();
        // 레이아웃 설정
        loginPanel.setLayout(new BorderLayout());
        idInput = new JTextField(15);
        loginButton = new JButton("로그인");
        // 이벤트 리스너 등록
        loginButton.addActionListener(this);
        label1 = new JLabel("대화명");
        // 패널에 위젯 구성
        loginPanel.add(label1, BorderLayout.WEST);
        loginPanel.add(idInput, BorderLayout.CENTER);
        loginPanel.add(loginButton, BorderLayout.EAST);

        // 로그아웃 패널 구성
        logoutPanel = new JPanel();
        // 레이아웃 설정
        logoutPanel.setLayout(new BorderLayout());
        label2 = new JLabel();
        logoutButton = new JButton("로그아웃");
        // 이벤트 리스너 등록
        logoutButton.addActionListener(this);
        // 패널에 위젯 구성
        logoutPanel.add(label2, BorderLayout.CENTER);
        logoutPanel.add(logoutButton, BorderLayout.EAST);

        // 입력 패널 구성
        msgPanel = new JPanel();
        // 레이아웃 설정
        msgPanel.setLayout(new BorderLayout());
        msgInput = new JTextField(30);
        // 이벤트 리스너 등록
        msgInput.addActionListener(this);
        exitButton = new JButton("종료");
        exitButton.addActionListener(this);
        // 패널에 위젯 구성
        msgPanel.add(msgInput, BorderLayout.CENTER);
        msgPanel.add(exitButton, BorderLayout.EAST);

        // 로그인/로그아웃 패널 선택을 위한 카드 레이아웃 패널
        tab = new JPanel();
        clayout = new CardLayout();
        tab.setLayout(clayout);
        tab.add(loginPanel, "login");
        tab.add(logoutPanel, "logout");

        // 메인 프레임 구성
        jframe = new JFrame("::멀티챗::");
        msgOut = new JTextArea("", 10, 30);
        // JTextArea의 내용을 수정하지 못하게 함. 즉, 출력 전용으로 사용
        msgOut.setEditable(false);
        // 수직 스크롤바는 항상 나타내고, 수평 스크롤바는 필요할 때만 나타나게 함
        JScrollPane jsp = new JScrollPane(msgOut, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        jframe.add(tab, BorderLayout.NORTH);
        jframe.add(jsp, BorderLayout.CENTER);
        jframe.add(msgPanel, BorderLayout.SOUTH);
        // 로그인 패널을 우선 표시
        clayout.show(tab, "login");
        // 프레임 크기 자동 설정
        jframe.pack();
        // 프레임 크기 조정 불가 설정
        jframe.setResizable(false);
        // 프레임 표시
        jframe.setVisible(true);

    }

    public void connectServer() {
        try {
            // 소켓 생성
            socket = new Socket("210.99.86.106", 8888);
            System.out.println("[Client]Server 연결 성공!!");

            // 입출력 스트림 생성
            inMsg = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            outMsg = new PrintWriter(socket.getOutputStream(), true);

            // 서버에 로그인 메시지 전달
            outMsg.println(id+"/"+"login");

            // 메시지 수신을 위한 스레드 생성
            thread = new Thread(this);
            thread.start();
        } catch(Exception e) {
            // e.printStackTrace();
            System.out.println("[MultiChatClient]connectServer() Exception 발생!!");
        }
    }

    // 이벤트 처리
    public void actionPerformed(ActionEvent arg0) {
        Object obj = arg0.getSource();

        // 종료 버튼 처리
        if(obj == exitButton) {
            System.exit(0);
        } else if(obj == loginButton) {
            id = idInput.getText();

            label2.setText("대화명 : " + id);
            clayout.show(tab, "logout");
            connectServer();
        } else if(obj == logoutButton) {
            // 로그아웃 메시지 전송
            outMsg.println(id + "/" + "logout");
            // 대화 창 클리어
            msgOut.setText("");
            // 로그인 패널로 전환
            clayout.show(tab, "login");
            outMsg.close();
            try {
                inMsg.close();
                socket.close();
            } catch(IOException e) {
                e.printStackTrace();
            }

            status = false;
        } else if(obj == msgInput) {
            // 메시지 전송
            outMsg.println(id + "/" + msgInput.getText());
            // 입력 창 클리어
            msgInput.setText("");
        }
    }

    public void run() {
        // 수신 메시지를 처리하는 변수
        String msg;
        String[] rmsg;

        status = true;

        while(status) {
            try {
                // 메시지 수신과 파싱
                msg = inMsg.readLine();
                rmsg = msg.split("/");

                // JTextArea에 수신된 메시지 추가
                msgOut.append(rmsg[0] + ">"+rmsg[1] + "\n");

                // 커서를 현재 대화 메시지에 표시
                msgOut.setCaretPosition(msgOut.getDocument().getLength());
            } catch(IOException e) {
                // e.printStackTrace();
                status = false;
            }
        }

        System.out.println("[MultiChatClient]" + thread.getName() + "종료됨");
    }

    public static void main(String[] args) {
        MultiChatClient mcc = new MultiChatClient("127.0.0.1");
    }
}

 

 

network.zip

↑지금까지의 소스파일

 

-직렬화와 역직렬화

통신을 할때는 주로 직렬을 사용. 수신쪽에서는 역직렬화를 수행해야 함.

따라서 객체를 직렬화하는 과정이 필요함.

 

-직렬화

//직렬화
import java.io.*;
import java.util.GregorianCalendar;
import java.util.Calendar;
class ObjectInputExample1
{
 public static void main(String[] args)
 {
  ObjectInputStream in = null;
  try{
   in = new ObjectInputStream(new FileInputStream("output.dat"));
   while(true){
    GregorianCalendar calendar = (GregorianCalendar)in.readObject();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH) + 1;
    int date = calendar.get(Calendar.DATE);
    System.out.println(year + "년" + month + "월" + date + "일");
   }
  }
  catch(FileNotFoundException fnfe){
   System.out.println("파일이 존재 X");
  }
  catch(EOFException eofe){
   System.out.println("끝!");
  }
  catch(IOException ioe){
   System.out.println("파일을 읽을 수가 없네..");
  }
  catch(ClassNotFoundException cnfe){
   System.out.println("해당 클래스가 존재를 안하네..");
  }
  finally{
   try{
    in.close();
   }
   catch(Exception e){};
  }
 }
}

import java.io.*;
import java.util.GregorianCalendar;
class ObjectOutputExample1
{
 public static void main(String[] args)
 {
  ObjectOutputStream out = null;
  try{
   out = new ObjectOutputStream(new FileOutputStream("output.dat"));
   out.writeObject(new GregorianCalendar(2006, 0, 14));
   out.writeObject(new GregorianCalendar(2006, 0, 15));
   out.writeObject(new GregorianCalendar(2006, 0, 16));
  }
  catch(IOException ioe){
   System.out.println("파일로 출력할 수 없네..");
  }
  finally{
   try{
    out.close();
   }
   catch(Exception e){}
  }
 }
}

 

 

//직렬화할때 희소한, 그런데 '유효'한 데이터만 골라서 저장하는 코드. 효율성을 위해서.

import java.io.*;
class DistrChart implements Serializable
{
 int arr[][];
 DistrChart(){
  arr = new int[10][10];
 }
 private void writeObject(ObjectOutputStream out) throws IOException{
  for(int row=0; row<arr.length; row++){
   for(int col=0; col<arr[0].length; col++){
    if(arr[row][col]!=0){
     out.writeInt(row);
     out.writeInt(col);
     out.writeInt(arr[row][col]);
    }
   }
  }
 }
 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{ 
  arr = new int[10][10];
  try{
   while(true){
    int row = in.readInt();
    int col = in.readInt();
    int data = in.readInt();
    arr[row][col] = data;
   }
  }
  catch(EOFException e){}
 }
}

import java.io.*;
class  ObjectOutputExample5
{
 public static void main(String[] args)
 {
  ObjectOutputStream out = null;
  try{
   out = new ObjectOutputStream(new FileOutputStream("output5.dat"));
   DistrChart obj = new DistrChart();
   obj.arr[0][1]=2;
   obj.arr[4][5]=5;
   obj.arr[6][1]=2;
   obj.arr[7][7]=7;
   obj.arr[8][4]=21;
   out.writeObject(obj);
  }
  catch(IOException ioe){
   System.out.println("파일로 출력할 수 x");
  }
  finally{
   try{
    out.close();
   }
   catch(Exception e){}
  }
 }
}

import java.io.*;
class ObjectInputExample5
{
 public static void main(String[] args)
 {
  ObjectInputStream in = null;
  try{
   in = new ObjectInputStream(new FileInputStream("output5.dat"));
   DistrChart obj = (DistrChart)in.readObject();
   for(int row=0; row<obj.arr.length; row++){
    for(int col=0; col<obj.arr[0].length; col++){
     System.out.printf("%3d", obj.arr[row][col]);
    }
    System.out.println();
   }
  }
  catch(FileNotFoundException fnfe){
   System.out.println("파일이  존재 x");
  }
  catch(EOFException eofe){
   System.out.println("끝");
  }
  catch(IOException ioe){
   System.out.println("파일 읽을 수 x");
  }
  catch(ClassNotFoundException cnfe){
   System.out.println("해당 클래스  존재 x");
  }
  finally{
   try{
    in.close();
   }
   catch(Exception e){};
  }
 }

}


'JAVA' 카테고리의 다른 글

애플릿  (0) 2013.06.14
GUI  (0) 2013.05.31
A태그 생성기 보완한 코드. 텍스트 파일로 저장하는거 연구중..  (0) 2013.05.25
JDBC 과제. 단순히 학사정보 시스템을 출력하는 예제  (0) 2013.05.25
JDBC  (0) 2013.05.24
,