스레드, 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");
}
}
↑지금까지의 소스파일
-직렬화와 역직렬화
통신을 할때는 주로 직렬을 사용. 수신쪽에서는 역직렬화를 수행해야 함.
따라서 객체를 직렬화하는 과정이 필요함.
-직렬화
//직렬화
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 |