반응형

# Java Socket(소켓)을 이용한 Multi-Chatting 프로그래밍

  • 멀티 채팅 구현 작업 진행.
  • 서버에서 HashMap 이용하여 멀티 채팅 구현.
  • 연결, 접속에 따른 알림 표시. 
  • 서버 : 서버에서는 HashMap 이용하여 클라이언트 관련 정보 담고, Thread를 이용하여 HashMap에 저장된 클라이언트 정보를 바탕으로 브로드 캐스팅 진행.
  • 클라이언트 : 보내는 쪽은 sender 라는 Thread 에 소켓 정보와 클라이언트 정보를 서버에 보내서 작업. 받는 쪽은 receiver 라는 Thread 에 소켓 정보를 담아 데이터 수신.

## 작업 소스

Project06F_MultiChatServer

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

public class Project06F_MultiChatServer {
	HashMap clients;
	
	Project06F_MultiChatServer() {
		clients = new HashMap();
		Collections.synchronizedMap(clients);	// 동기화를 위해 사용.
	}
	
	public void start() {
		ServerSocket serverSocket = null;
		Socket socket = null;
		
		try {
			serverSocket = new ServerSocket(9999);
			System.out.println("서버 실행...");
			
			while (true) {
				socket = serverSocket.accept();	// 클라이언트의 정보를 알고 있는 소켓.
				System.out.println(socket.getInetAddress() + ":" + socket.getPort() + " 연결.");
				
				ServerReceiver thread = new ServerReceiver(socket);
				thread.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 브로드캐스팅 기능
	void sendToAll(String msg) {
		Iterator iterator = clients.keySet().iterator();
		
		while (iterator.hasNext()) {
			try {
				DataOutputStream out = (DataOutputStream) clients.get(iterator.next());
				out.writeUTF(msg);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] agrg) {
		new Project06F_MultiChatServer().start();
	}
	
	// inner class (클래스 내부에 있는 클래스를 의미)
	public class ServerReceiver extends Thread {
		Socket socket;
		DataInputStream in;
		DataOutputStream out;
		
		ServerReceiver(Socket socket) {
			this.socket = socket;
			
			try {
				in = new DataInputStream(socket.getInputStream());
				out = new DataOutputStream(socket.getOutputStream());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		public void run() {
			String name = "";
			
			try {
				name = in.readUTF();
				
				// HashMap 에 사용자 이름 존재유무 체크.
				if (clients.get(name) != null) {
					out.writeUTF("이미 존재하는 이름입니다 : " + name);
					out.writeUTF("다른 이름으로 다시 연결해주세요.");
					System.out.println(socket.getInetAddress() + ":" + socket.getPort() + " 연결 종료.");
					in.close();
					out.close();
					socket.close();
					socket = null;
				} else {
					sendToAll("#" + name + " 님께서 입장하셨습니다.");
					clients.put(name, out);
					
					while (in != null) {
						sendToAll(in.readUTF());
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (socket != null) {
					sendToAll("#" + name + " 님께서 접속을 종료하였습니다.");
					clients.remove(name);
					System.out.println(socket.getInetAddress() + ":" + socket.getPort() + " 연결 종료.");
				}
			}
		}
	}
}

Project06F_MultiChatClient

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Project06F_MultiChatClient {
	public static void main(String[] args) {
		try {
			Socket socket = new Socket("127.0.0.1", 9999);
			Scanner scanner = new Scanner(System.in);
			
			System.out.println("name : ");
			String name = scanner.nextLine();
			
			Thread sender = new Thread(new ClientSender(socket, name));
			Thread receiver = new Thread(new ClientReceiver(socket));
			sender.start();
			receiver.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// inner class
	static class ClientSender extends Thread {
		Socket socket;
		DataOutputStream out;
		String name;
		
		ClientSender(Socket socket, String name) {
			this.socket = socket;
			this.name = name;
			try {
				out = new DataOutputStream(socket.getOutputStream());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		public void run() {
			Scanner scanner = new Scanner(System.in);
			
			try {
				if (out != null) {
					out.writeUTF(name);
				}
				
				while (out != null) {
					String message = scanner.nextLine();
					
					if (message.equals("quit")) {
						break;
					}
					out.writeUTF("[" + name + "] : " + message);
				}
				out.close();
				socket.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	static class ClientReceiver extends Thread {
		Socket socket;
		DataInputStream in;
		
		ClientReceiver(Socket socket) {
			this.socket = socket;
			
			try {
				in = new DataInputStream(socket.getInputStream());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		public void run() {
			while (in != null) {
				try {
					System.out.println(in.readUTF());
				} catch (Exception e) {
					e.printStackTrace();
					break;
				}
			}
			
			try {
				in.close();
				socket.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

## 실행방법

서버 실행

  • 관리자 권한으로 cmd 실행
  • 워크스페이스의 bin 폴더까지 들어간 후 java Project06F_MultiChatServer 입력하여 서버 실행.

클라이언트 실행

  • 관리자 권한으로 cmd 실행
  • 워크스페이스의 bin 폴더까지 들어간 후 java Project06F_MultiChatClient 입력하여 서버 실행. (멀티 채팅이므로 cmd 하나 더 실행해서 동일하게 실행)
반응형
반응형

# Java Socket(소켓) Multi-Chatting 프로그래밍_소켓이 만들어지는 과정(TCP 3-way Handshake)

  • 소켓은 자바 뿐만 아니라 다른 언어에서도 빈번하게 접하는 용어.
  • 데이터 통신을 위해 필요.

## 소켓이 만들어 지는 과정 (TCP 3-way Handshake)

  • 소켓 : IP 주소와 PORT 번호를 갖고 있는 객체 (class)
  • TCP 3-way Handshake : 소켓이 만들어 지는 과정.
  • PC 간의 데이터 통신 등에 소켓을 활용.
  • 데이터 통신을 위해 소켓에 상대방의 정보를 알고 있어야 한다.
  • 자바에서는 아래와 같이 소켓이 만들어진다.
클라이언트 : 요청자.
서버 : 정보 제공자.


1. 첫번째
- 서버 소켓 생성 : 클라이언트의 접속을 받아들이기 위한 소켓.
- 서버 소켓 정보 : 서버로 접속하기 위한 서버 IP 주소, PORT번호를 포함.
- 클라이언트는 서버 소켓을 바탕(서버 IP 주소, PORT번호)으로 서버에 접속.
(접속을 시도할때 클라이언트는 본인의 정보가 담긴 소켓을 가지고 간다.) 


2. 두번째 (클라이언트 식별, 바인딩)
- 서버 소켓은 식별, 안내 역할. (실제 통신하는 소켓이 아님) 
- 식별된 클라이언트와 통신을 위한 소켓 생성.
(서버에서 만들어진 해당 소켓에는 클라이언트의 정보가 담겨있다.)


3. 세번째 (서버 정보 전달)
- 클라이언트가 통신을 할 수 있도록 서버의 정보를 전달하여 클라이언트의 소켓에 담는다.


=>
결국, 서로(상대방)의 정보를 갖고있는 클라이언트 소켓, 서버 소켓을 바탕으로 통신.

 

# Java Socket(소켓) Multi-Chatting 프로그래밍_자바에서 소켓 만들기 (ECHO)

## 자바에서 소켓 만들기

  • 자바에는 서버 소켓 (Server Socket), 소켓 (Socket) 이 존재 하며, import java.net.* 에 존재 한다.
  • 서버 소켓 : 클라이언트의 접속을 대기하는 소켓. (서버 소켓은 통신 불가능, 통신은 소켓으로 가능)
  • 서버는 LIST, HASHMAP 에 소켓 정보를 넣어서 관리.
// 서버 소켓 생성
ServerSocket ss = new ServerSocket(9000);


// accept : 클라이언트의 접속 대기. (Blocking Method)
// 식별 후 수락하여 바인딩(소켓생성). 
// 해당 소켓은 클라이언트의 정보를 알고 있는 소켓.
Socket sock = ss.accept();	


// 생성된 소켓정보를 전송
// 클라이언트는 넘겨받은 서버 IP, PORT 정보를 바탕으로 소켓 생성.
// 해당 소켓은 서버의 정보를 알고 있는 소켓.
Socket sock = new Socket("172.173.8.1", 9000);
  • 3-Way-Handshake 요약
1. 접속대기 (Blocking Method)

2. 클라이언트 식별

3. 수락

4. 바인딩 (소켓 생성)

5. 생성된 소켓정보 전송

## 소켓을 이용한 ECHO(메아리) 프로그램 만들기.

  • 클라이언트 요청에 서버가 응답하는 ECHO 프로그램. (소켓의 가장 기본)

## 작업 소스

Project06A_Server

import java.io.*;
import java.net.*;

public class Project06A_Server {
	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		
		try {
			serverSocket = new ServerSocket(9999);
			System.out.println("SERVER READY........");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		while (true) {
			try {
				// 접속 대기.
				// 해당 소켓은 클라이언트의 정보를 알고 있는 소켓.
				Socket socket = serverSocket.accept();
				System.out.println("클라이언트 연결 성공!");
				
				// 클라이언트부터 메세지 읽어오기.
				InputStream in = socket.getInputStream();
				DataInputStream dis = new DataInputStream(in);	// 한글 메세지 깨짐 방지 위해 생성.
				String message = dis.readUTF();
				
				// 클라이언트에게 메세지 전달하기.
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);	// 한글 메세지 깨짐 방지 위해 생성.
				dos.writeUTF("[ECHO] " + message + " (서버에서 전송된 메세지.)");
				
				dos.close();
				dis.close();
				socket.close();
				System.out.println("소켓 종료.");				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

Project06A_Client

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class Project06A_Client {
	public static void main(String[] args) {
		try {
			// 해당 소켓에는 서버 소켓 정보가 저장됨.
			Socket socket = new Socket("127.0.0.1", 9999);	// --> accept()
			System.out.println("연결 성공!");
			
			// ECHO 메세지 입력.
			Scanner scanner = new Scanner(System.in);
			String message = scanner.nextLine();
			
			// 서버에 메세지 전달.
			OutputStream out = socket.getOutputStream();
			DataOutputStream dos = new DataOutputStream(out);
			dos.writeUTF(message);
			
			// 서버로부터 전달받은 응답.
			InputStream in = socket.getInputStream();
			DataInputStream dis = new DataInputStream(in);
			System.out.println("서버로부터 받은 메세지 : " + dis.readUTF());
			
			dis.close();
			dos.close();
			socket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

## 실행 방법

  • cmd 관리자 권한으로 실행.
  • 프로젝트 폴더 내 bin 폴더 까지 진입 후 아래와 같이 입력하여 실행. (먼저 server 실행, 이후 client 실행.)
java 실행할class파일명
반응형
반응형

# Java MQTT Client 만들기_Java 에서 MQTT 연동하기 (Java 와 MQTT 연동 DHT11 센서 데이터 모니터링 및 LED 제어)

  • IoT(사물인터넷)과 관련 됨. (사물 인터넷에서 중요한 부분은 통신)
  • 별도의 IoT(사물인터넷) 연동하진 않고 Java 와 MQTT 연동하는 소스 작업 진행.

## 준비물

## 작업소스

Project05_F.java (메인)

import kr.javatpc.MqttClass;

public class Project05_F {
	public static void main(String[] args) {
		new MqttClass();
	}
}

MqttClass.java

package kr.javatpc;

import java.util.UUID;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

public class MqttClass implements MqttCallback {
	
	private MqttClient client = null;
	public MqttClass() {
		new Thread(task1).start();
	}
	
	private ReceiveEventListener listener = null;
	
	Runnable task1 = new Runnable() {
		@Override
		public void run() {
			try {
				String clientId = UUID.randomUUID().toString();
				client = new MqttClient("tcp://본인IP주소:1883", clientId);
				MqttConnectOptions connopt = new MqttConnectOptions();
				connopt.setCleanSession(true);
				client.connect(connopt);
				client.setCallback(MqttClass.this);
				client.subscribe("dht11");
				new IoTFrame(MqttClass.this);
			} catch(MqttException e) {
				System.out.println("ERRO"+e.getStackTrace());
			}
		}
	};
	
	public void sendMessage(String payload) {
		MqttMessage message = new MqttMessage();
		message.setPayload(payload.getBytes());
		try {
			if (client.isConnected()) {
				client.publish("led", message);
			}
		} catch(MqttException e) {
			System.out.println("error1 : " + e.getStackTrace());
		}
	}
	
	@Override
	public void connectionLost(Throwable arg0) {
		try {
			System.out.println("disconect");
			client.close();
		} catch(MqttException e) {
			System.out.println("error" + e.getMessage());			
		}
	}
	
	@Override
	public void deliveryComplete(IMqttDeliveryToken arg0) {
		
	}
	
	public void setMyEventListner(ReceiveEventListener listener) {
		this.listener = listener;
	}
	
	public void messageArrived(String topic, MqttMessage msg) throws Exception {
		listener.recvMsg(topic, msg);
	}
}

IoTFrame.java

package kr.javatpc;

import java.awt.BorderLayout;
import java.awt.ScrollPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;

public class IoTFrame extends JFrame implements 
					ActionListener, ReceiveEventListener {
	private static final long serialVersionUID = 1L;
	private JTextField tmp = new JTextField(10);
	private JTextField hum = new JTextField(10);
	private JButton ledOn = new JButton("LED ON");
	private JButton ledOff = new JButton("LED OFF");
	private JLabel msg = new JLabel("온도/습도 모니터링");
	private JTextArea out = new JTextArea(20, 40);
	private JPanel panel = new JPanel();
	private JPanel panel1 = new JPanel();
	private JPanel panel2 = new JPanel();
	private ScrollPane sp = new ScrollPane();
	private MqttClass mqtt = null;
	
	public IoTFrame(MqttClass mqtt) {
		this();
		this.mqtt = mqtt;
		this.mqtt.setMyEventListner(this);
	}
	
	public IoTFrame() {
		super("MQTT 사물인터넷 통신 프로젝트");
		setSize(400, 400);
		panel.add(msg);
		panel.add(ledOn);
		panel.add(ledOff);
		panel1.add(tmp);
		panel1.add(hum);
		sp.add(out);
		add(BorderLayout.NORTH, panel);
		add(BorderLayout.CENTER, sp);
		add(BorderLayout.SOUTH, panel1);
		
		ledOn.addActionListener(this);
		ledOff.addActionListener(this);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	@Override
	public void recvMsg(String topic, MqttMessage msg) {
		System.out.println(topic+","+msg);
		String append = out.getText();
		out.setText(topic+","+msg+"\n"+append);
		JSONObject obj = new JSONObject(new String(msg.getPayload()));
		tmp.setText("온도 : " + obj.get("tmp").toString());
		tmp.setText("습도 : " + obj.get("hum").toString());
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		JButton b = (JButton) e.getSource();
		if (b.getText().equals("LED_NO")) {
			mqtt.sendMessage("1");
		} else if (b.getText().equals("LED_OFF")) {
			mqtt.sendMessage("2");
		}
	}
}

ReceiveEventListener.java (인터페이스)

package kr.javatpc;

import org.eclipse.paho.client.mqttv3.MqttMessage;

public interface ReceiveEventListener {
	public void recvMsg(String topic, MqttMessage msg);
}

## 실습

1. MQTT 서버 구동

  • 관리자 권한으로 cmd 실행.
  • 아래와 같이 입력하여 mosquitto 서버 구동.
cd..

cd..

MQTTProject\mosquitto 

mosquitto -v

2. 수신자 서버 구동 (온도, 습도 수신자)

  • 관리자 권한으로 cmd 실행.
  • 아래와 같이 입력하여 mosquitto 서버 구동.
cd..

cd..

cd MQTTProject\mosquitto

mosquitto_sub -t dht11 -p 1883

3. 수신자 서버 구동(LED 조작 수신자)

  • 관리자 권한으로 cmd 실행.
  • 아래와 같이 입력하여 mosquitto 서버 구동.
cd..

cd..

MQTTProject\mosquitto

mosquitto_sub -t led -p 1883

4. 발행자

  • 원래는 아두이노로 연동하여 테스트 해야 하나, 임의의 발행자 구동하여 테스트 진행.
  • 아래와 같이 데이터 입력하여 테스트.
cd..

cd..

cd MQTTProject\mosquitto

mosquitto_pub -t dht11 -p 1883 -m "{\"tmp\":24,\"hum\":67}\"

반응형
반응형

# Java MQTT Client 만들기_Mosquitto MQTT broker 설치 및 서버구동

  • MQTT : 메세지를 중계해주는 프로토콜.
  • 아두이노 등을 이용하여 포트 번호 등의 정보를 이용, 통신하여 온도, 습도 등 원하는 정보 표시가능.

## Mosquitto MQTT broker

Mosquitto MQTT broker 설치

  • 운영체제에 맞는 프로그램 다운로드 진행.

  • 다운로드 받은 설치 파일 실행, 경로를 C드라이브에 MQTTProject 폴더 생성하여 지정 후 설치진행.

Mosquitto MQTT broker 서버 구동

  • 관리자 권한으로 cmd 실행.
  • 아래 명령어 입력하여 MQTT 서버 구동 
mosquitto -v

구독자(subscriber) 실행

  • 서버 구동한건 내려놓고, 별도로 관리자 권한으로 cmd 실행
  • 아래 명령어 입력하여 실행 - 수신 대기 창.

  • 외부에서 연결 시에는 아래와 같이 입력하여 진행
mosquitto_sub -h MQTT서버ip주소 -t iot -p 1883

발행자(publisher) 실행

  • 아래 명령어 입력하여 실행 - 메시지(토픽) 발행 창.

  • 이렇게 하면 아래와 같이 구독자에게 입력한 내용이 전달된다. (JSON 등의 형식으로도 전달 가능)

반응형

+ Recent posts