| Server | ↔ JSON 형태로만 | Clinet |
|---|---|---|
| 클라이언트의 접속을 기다린다. | new Socket(IP,PORT) | |
| RequestDto | ← Req (Join (username)) | Singleton |
| ResponseDto | → Response | |
| Socket List | ↗ |
Server
package simplechatting2.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import lombok.Data;
import simplechatting2.dto.JoinReqDto;
import simplechatting2.dto.JoinRespDto;
import simplechatting2.dto.MessageReqDto;
import simplechatting2.dto.MessageRespDto;
import simplechatting2.dto.RequestDto;
import simplechatting2.dto.ResponseDto;
@Data
class ConnectedSocket extends Thread{
private static List<ConnectedSocket> socketList = new ArrayList<>();
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
private Gson gson;
private String username;
public ConnectedSocket(Socket socket) {
this.socket = socket;
gson = new Gson(); // gson 생성
socketList.add(this);
}
@Override
public void run() {
try {
inputStream = socket.getInputStream(); // 들어올 문을 열어줌
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
while(true) {
String request = in.readLine(); // requestDto(JSON)
RequestDto requestDto = gson.fromJson(request, RequestDto.class);
switch(requestDto.getResource()) {
case "join" :
JoinReqDto joinReqDto = gson.fromJson(requestDto.getBody(), JoinReqDto.class);
username = joinReqDto.getUsername();
List<String> connectedUsers = new ArrayList<>();
for(ConnectedSocket connectedSocket : socketList) {
connectedUsers.add(connectedSocket.getUsername());
}
JoinRespDto joinRespDto = new JoinRespDto(username + "님이 접속하였습니다.",connectedUsers);
sendToAll(requestDto.getResource(), "ok",gson.toJson(joinRespDto));
break;
case "sendMessage":
MessageReqDto messageReqDto = gson.fromJson(requestDto.getBody(), MessageReqDto.class);
if(messageReqDto.getToUser().equalsIgnoreCase("all")) {
String message = messageReqDto.getFromUser() + "[전체]: " + messageReqDto.getMessageValue();
MessageRespDto messageRespDto = new MessageRespDto(message);
sendToAll(requestDto.getResource(), "ok", gson.toJson(messageRespDto));
}
break;
}
}
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void sendToAll(String resource,String status,String body) throws IOException {
ResponseDto responseDto = new ResponseDto(resource, status, body);
for(ConnectedSocket connectedSocket : socketList) {
OutputStream outputStream = connectedSocket.getSocket().getOutputStream();
PrintWriter out = new PrintWriter(outputStream,true);
out.println(gson.toJson(responseDto));
}
}
}
public class ServerApplication {
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(9090);
System.out.println("====<<< 서버 실행 >>>====");
while(true) {
Socket socket = serverSocket.accept(); // 클라이언트의 접속을 기다리는 녀석 // 연결버튼 누를때 까지
ConnectedSocket connectedSocket = new ConnectedSocket(socket); //쓰레드
connectedSocket.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("====<<< 서버 종료 >>>====");
}
}
}
Client
package simplechatting2.client;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import com.google.gson.Gson;
import lombok.Getter;
import simplechatting2.dto.JoinReqDto;
import simplechatting2.dto.MessageReqDto;
import simplechatting2.dto.RequestDto;
@Getter
public class ChattingClient extends JFrame {
// ChattingClient singleton 생성
private static ChattingClient instance;
public static ChattingClient getInstance() {
if(instance == null) {
instance = new ChattingClient();
}
return instance;
}
private Socket socket;
private Gson gson;
private String username;
private JPanel contentPane;
private JTextField ipInput;
private JTextField portInput;
private JTextArea contentView;
private JTextField messageInput;
private JList userList;
private DefaultListModel<String> userListModel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ChattingClient frame = ChattingClient.getInstance();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private ChattingClient() {
gson = new Gson();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 587, 444);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
ipInput = new JTextField();
ipInput.setText("127.0.0.1");
ipInput.setBounds(337, 11, 97, 32);
contentPane.add(ipInput);
ipInput.setColumns(10);
JButton connectButton = new JButton("연결");
connectButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
String ip = null; // 텍스트 필드에 있는 값을 가져옴
int port = 0; // 텍스트 필드에 있는 값을 가져옴
ip = ipInput.getText();
port = Integer.parseInt(portInput.getText());
try {
socket = new Socket(ip, port); //client → server단의 serverSocket.accept(); 에게 전달 →
JOptionPane.showMessageDialog(null,
socket.getInetAddress().toString().replaceAll("/", "") + "서버 접속" ,
"접속성공",
JOptionPane.INFORMATION_MESSAGE);
ClientRecive clientRecive = new ClientRecive(socket);
clientRecive.start();
username = JOptionPane.showInputDialog(null,"사용자 이름을 입력해 주세요.","이름입력",JOptionPane.INFORMATION_MESSAGE);
JoinReqDto joinReqDto = new JoinReqDto(username);
String joinReqDtoJson = gson.toJson(joinReqDto);
RequestDto requestDto = new RequestDto("join", joinReqDtoJson);
String requestDtoJson = gson.toJson(requestDto);
OutputStream outputStream = socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream,true);
out.println(requestDtoJson);
}catch (ConnectException e1) {
JOptionPane.showMessageDialog(null,
"서버 접속 실패" ,
"접속실패",
JOptionPane.ERROR_MESSAGE);
}catch (UnknownHostException e1) {
e1.printStackTrace();
}catch (IOException e1) {
e1.printStackTrace();
}
}
});
connectButton.setBounds(501, 10, 65, 33);
contentPane.add(connectButton);
portInput = new JTextField();
portInput.setText("9090");
portInput.setBounds(446, 11, 43, 32);
contentPane.add(portInput);
portInput.setColumns(10);
JScrollPane contentScroll = new JScrollPane();
contentScroll.setBounds(12, 10, 313, 358);
contentPane.add(contentScroll);
contentView = new JTextArea();
contentScroll.setViewportView(contentView);
JScrollPane userListScroll = new JScrollPane();
userListScroll.setBounds(337, 53, 222, 315);
contentPane.add(userListScroll);
userListModel = new DefaultListModel<>();
userList = new JList(userListModel);
userListScroll.setViewportView(userList);
JScrollPane messageScroll = new JScrollPane();
messageScroll.setBounds(12, 378, 488, 23);
contentPane.add(messageScroll);
messageInput = new JTextField();
messageInput.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
if(!messageInput.getText().isBlank()) {
try {
OutputStream outputStream = socket.getOutputStream(); // 소켓안에 outputStream 들어있음
PrintWriter out = new PrintWriter(outputStream,true);
MessageReqDto messageReqDto =
new MessageReqDto("all", username, messageInput.getText());
sendRequest("sendMessage", gson.toJson(messageReqDto));
messageInput.setText("");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} //
}
}
}
});
messageScroll.setViewportView(messageInput);
JButton sendButton = new JButton("전송");
sendButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(!messageInput.getText().isBlank()) {
try {
OutputStream outputStream = socket.getOutputStream(); // 소켓안에 outputStream 들어있음
PrintWriter out = new PrintWriter(outputStream,true);
MessageReqDto messageReqDto =
new MessageReqDto("all", username, messageInput.getText());
sendRequest("sendMessage", gson.toJson(messageReqDto));
messageInput.setText("");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} //
}
}
});
sendButton.setBounds(505, 378, 61, 23);
contentPane.add(sendButton);
}
private void sendRequest(String resouce, String body) {
OutputStream outputStream;
try {
outputStream = socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream,true);
RequestDto requestDto = new RequestDto(resouce, body);
out.println(gson.toJson(requestDto));
} catch (IOException e) {
e.printStackTrace();
}
}
}
package simplechatting2.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import simplechatting2.dto.JoinRespDto;
import simplechatting2.dto.MessageRespDto;
import simplechatting2.dto.ResponseDto;
@RequiredArgsConstructor
public class ClientRecive extends Thread {
private final Socket socket;
private InputStream inputStream;
private Gson gson;
@Override
public void run() {
try {
inputStream = socket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
gson = new Gson();
while(true) {
String request = in.readLine();
ResponseDto responseDto = gson.fromJson(request, ResponseDto.class);
switch (responseDto.getResource()) {
case "join" :
JoinRespDto joinRespDto = gson.fromJson(responseDto.getBody(), JoinRespDto.class);
ChattingClient.getInstance().getContentView().append(joinRespDto.getWelcomeMessage()+"\n");
ChattingClient.getInstance().getUserListModel().clear();
ChattingClient.getInstance().getUserListModel().addAll(joinRespDto.getConnectedUsers());
break;
case "sendMessage" :
MessageRespDto messageRespDto = gson.fromJson(responseDto.getBody(),MessageRespDto.class);
ChattingClient.getInstance().getContentView().append(messageRespDto.getMessageValue()+ "\n");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Dto
package simplechatting2.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class JoinReqDto {
private String username;
}
package simplechatting2.dto;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class JoinRespDto {
private String welcomeMessage;
private List<String> connectedUsers;
}
package simplechatting2.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class MessageReqDto {
private String toUser;
private String fromUser;
private String messageValue;
}
package simplechatting2.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class MessageRespDto {
private String messageValue;
}
package simplechatting2.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class RequestDto {
private String resource;
private String body;
}
package simplechatting2.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class ResponseDto {
private String resource;
private String status;
private String body;
}
