* 저도 공부중인 부분이라, 자세히는 모르지만 일단 소스가 동작하고
방이 나눠지는 것을 확인 했습니다.
순서
서버 ( 자바 이클립스 )
1) 접속할 포트와 소켓을 열어준다. ( 무한 반복 )
2) 접속한 소캣의 정보를 저장해둔다.
3) 저장 한 소캣의 입력 출력 스트림을 열어준다 ( 위의 무한 반복 안에 생성 )
( 메세지 송 수신 관련 스트림입니다. DataInpuStream 과 DataOutputStream 를 사용합니다. 다른것도 사용할 수 있습니다. )
4) 메세지를 수신할 스레드를 작성한다.
5) 수신한 메세지를 처리하는 로직을 짠다 ( ex 방나누기 1:1 채팅 그룹채팅 등을 구분할수 있는 구분자들 )
6) 보내고 싶은 상대방 쪽스트림에다가 데이터를 전송한다.
----------------------------------------------------------------------------------------------------------------------------------------
클라이언트쪽
1) 소캣 객체를 만든다
Socket socket = new Socket(host,port);
host에는 목적지의 주소 port에는 목적지가 열어놓은 포트번호 ( 여기서 목적지는 서버쪽이 된다 )
발생 예외 )
- UnknownHostException : host로 서버를 찾을 수 없을 때
- IOException : 네트워크 문제로 소켓을 생성할 수 없을 때
- SecurityException : 보안 매니저에 의해 연결이 허용되지 않을 때
------------------------------------------------------------------------------------------------------------------------------------
자바 ( 서버 코드 )
public class chatSever {
// 접속자 정보를 저장할 리스트
ArrayList<user_data> clients;
user_data uData;
// 서버 소캣 ( 서비스용 소켓 )
private ServerSocket severSocket = null;
public chatSever() {
// 연결부에서 리스트 생성
clients = new ArrayList<>();
// clients 동기화
Collections.synchronizedList(clients);
}
public static void main(String[] args) {
new chatSever().start(); // 쓰레드의 시작
}
// ( 접속 ) 메인함수에서 시작하는 메소드
private void start() {
// 서버에서 열어주는 포트 번호 ( 랜덤 값 가능 )
int port = 9999;
Socket socket = null;
try {
// 서버 소캣을 생성후 while문으로 진입 하여 accept(대기)
// 접속시 ip 주소를 획득하고 출려한뒤 MultiThread를 실행한다.
// 서버 소캣을 생성
severSocket = new ServerSocket(port);
System.out.println("서버 소캣 생성 : 접속 대기중");
while(true) {
socket = severSocket.accept(); //접속 대기중 ( 대기하고 있다가 들어오면 소켓을 만들고 )
// 클라에서 접속하게 되면 통신회선이 만들어지면서 데이터를 주고 받을 수 있다.
/* // ip 주소 얻기
InetAddress ip = socket.getInetAddress();
System.out.println(ip+ " 접속 ");*/
// 쓰레드에서 객체를 주고받을 Stream 생성자를 선언한다. ( 생성자 )
// run에서 접속한 주소를 받아와 출력하고 클라이언트에 정보를 넘겨주고 clients에게 ip 주소 mac 주소를 보낸다 .
// 사용자가 들어올때마다 쓰레드를 생성및 실행
//( 서버의 성능이 좋아야겟지 100명이 들어오면 쓰레드가 100개가 돌태니까 )
new MultiThread(socket).start(); // MultiThread 의 run()실행
}
} catch (Exception e) {
e.printStackTrace();
}
} // start() 끝
// 내부클래스 ( 사용자가 접속할때마다 쓰레드를 생성해주는 클래스 )
class MultiThread extends Thread{
Socket socket = null;
String msg = null;
String mac = null;
DataInputStream in;
DataOutputStream out;
public MultiThread ( Socket socket) {
this.socket = socket;
// 데이터 입출력을 위한 스트림 실행
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
}catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
// 처음에 한번만 받을건데 이때 정보를 가지고 오자 !
mac = in.readUTF(); //수신 ( 클라가 글을 쓰면 서버로 온다 ) 클라 - 서버 - 클라
// 초기에 한번만 접속자의 정보를 받는것.
System.out.println("접속자 정보들 : "+mac);
// 리스트에 추가 ( 클라이언트의 정보를 저장 아이디를 key로 쓰자 )
String [] filter;
filter = mac.split("@");
// ( 기존 방에 있는 아이디가 있는지 탐색후 없을시 저장한다 )
//클라이언트의 정보를 만들어서 리스트에 추가
uData = new user_data(socket,Integer.parseInt(filter[0]),filter[1],out);
clients.add(uData);
// 접속자 확인
System.out.println(filter[1]+"님이"+filter[0]+"번 방에 입장하셨습니다.");
// 메세지 보내기 ( 클라 쪽으로 방에 접속했다라는 메세지인데 , 나중에 단체 채팅일 경우에 써 보자 );
// **** sendMsg( mac + "접속");
while (in != null) {
try {
String temp = in.readUTF(); //수신된 메세지
sendMsg(temp);
System.out.println("MultiThread 의 런 "+ temp);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}//run 의 끝
// 서버가 클라이언트에게 보낸다 . ( 지금은 다보내고 있는데, 그룹인 경우 구분자를 줘서 한다 )
void sendMsg ( String msg) {
// 방번호, 보낸사람, 받는 사람, 메세지
String [] filt1 = msg.split("@");
// 메세지 전송시 날짜
SimpleDateFormat mFormat = new SimpleDateFormat("aa hh:mm");
// 클라이언트들의 정보를 모은 집합
for ( int i = 0 ; i < clients.size() ; i++) {
try {
// 클라이언트들의 정보를 모은 집합에서 같은 방에 있고 자신이 아닌 상대방에게 보내는 경우에 메세지를 보낸다 .
// 방번호가 같고
if ( Integer.parseInt(filt1[0]) == clients.get(i).roomNo ) {
// 본인이 아닌 모든 사람에게 보낸다.
if( !filt1[1].equals(clients.get(i).Userid)) {
// 클라이언트의 OutputStream 을 저장
OutputStream dos = clients.get(i).output;
DataOutputStream out = new DataOutputStream(dos);
// 현재 시간 받아오기
long mNow;
Date mDate;
mNow = System.currentTimeMillis();
mDate = new Date(mNow);
String time = mFormat.format(mDate);
// 클라이언트에 메세지를 전송 ( 보낸 사람과, 내용 )
out.writeUTF(filt1[1]+"@"+filt1[3]+"@"+time);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
} // sendMsg 끝
} // MultiThread 끝
}
------------------------------------------------------------------------------------------------------------------------------------
user_data 클래스
public class user_data {
Socket userSocket;
int roomNo;
String Userid;
DataOutputStream output;
public user_data(Socket userSocket,int roomNo, String UserId, DataOutputStream output) {
this.userSocket = userSocket;
this.roomNo = roomNo;
this.Userid = UserId;
this.output = output;
}
}
------------------------------------------------------------------------------------------------------------------------------------
안드로이드
< 수신 핸들러 >
/ 서버로부터 수신한 메세지를 처리하는 곳 ( AsyncTesk를 써도됨 )
msgHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 1111){
// 메세지가 왔다면.
Toast.makeText(context, "메세지 : "+msg.obj.toString(), Toast.LENGTH_SHORT).show();
Log.d("받은 메세지 ",msg.obj.toString());
msgFilter = msg.obj.toString().split("@");
// 수신 1
messageContent = new chattingMessageContent(1, msgFilter[0], targetNickName, msgFilter[1], msgFilter[2]);
messageData.add(messageContent);
chattingRoomAdapter.notifyDataSetChanged();
}
}
};
< 메세지 보내기 이벤트 >
// 채팅 입력 이벤트
public void setSendBtn() {
ImageView enterRoomChattingSend = (ImageView) findViewById(R.id.enterRoomChattingSend);
enterRoomChattingSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText enterRoomChattingEditText = (EditText) findViewById(R.id.enterRoomChattingEditText);
String message = enterRoomChattingEditText.getText().toString();
if (message == null || TextUtils.isEmpty(message) || message.equals("")) {
Toast.makeText(chattingRoom.this, "메세지를 입력해주세요", Toast.LENGTH_SHORT).show();
} else {
int mode = 2;
String senderId = loginUserId;
String senderNick = loginUserNick;
// 현재 시간 받아오기
long mNow;
Date mDate;
mNow = System.currentTimeMillis();
mDate = new Date(mNow);
String time = mFormat.format(mDate);
messageContent = null;
messageContent = new chattingMessageContent(mode, senderId, senderNick, message, time);
messageData.add(messageContent);
chattingRoomAdapter.notifyDataSetChanged();
// 메세지 보내주기
send = new SendThread(socket,message);
send.start();
// 에디트 텍스트 비워주기
enterRoomChattingEditText.setText(null);
// 키보드 내려주기
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(enterRoomChattingEditText.getWindowToken(),0);
Toast.makeText(chattingRoom.this, "전송", Toast.LENGTH_SHORT).show();
}
}
});
}
< 서버에 접속 >
// 내부클래스 ( 접속용 )
class SocketClient extends Thread{
DataInputStream in = null;
DataOutputStream out = null;
String roomAndUserData; // 방 정보 ( 방번호 / 접속자 아이디 )
public SocketClient(String roomAndUserData){
this.roomAndUserData = roomAndUserData;
}
public void run(){
try {
// 채팅 서버에 접속 ( 연결 ) ( 서버쪽 ip와 포트 )
socket = new Socket(ipad2,port);
// 메세지를 서버에 전달 할 수 있는 통로 ( 만들기 )
output = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
// 서버에 초기 데이터 전송 ( 방번호와 접속자 아이디가 담겨서 간다 ) - 식별자 역할을 하게 될 거임.
output.writeUTF(roomAndUserData);
// (메세지 수신용 쓰레드 생성 ) 리시브 쓰레드 시작
recevie = new ReceiveThread(socket);
recevie.start();
}catch (Exception e){
e.printStackTrace();
}
}
} //SocketClient의 끝
< 메세지 전송 >
// 내부 클래스 ( 메세지 전송용 )
class SendThread extends Thread{
Socket socket;
String sendmsg;
DataOutputStream output;
public SendThread(Socket socket, String sendmsg ){
this.socket = socket;
this.sendmsg =sendmsg;
try {
// 채팅 서버로 메세지를 보내기 위한 스트림 생성.
output = new DataOutputStream(socket.getOutputStream());
}catch (Exception e){
e.printStackTrace();
}
}
// 서버로 메세지 전송 ( 이클립스 서버단에서 temp 로 전달이 된다.
public void run(){
try {
if ( output != null){
if (sendmsg != null){
// 여기서 방번호와 상대방 아이디 까지 해서 보내줘야 할거같다 .
// 서버로 메세지 전송하는 부분
output.writeUTF(roomNo+"@"+loginUserId+"@"+targetId+"@"+sendmsg);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
< 메세지 수신 >
// ( 메세지 수신용 ) - 서버로부터 받아서, 핸들러에서 처리하도록 할 거.
class ReceiveThread extends Thread{
Socket socket = null;
DataInputStream input = null;
public ReceiveThread(Socket socket) {
this.socket = socket;
try {
// 채팅 서버로부터 메세지를 받기 위한 스트림 생성.
input = new DataInputStream(socket.getInputStream());
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (input != null){
// 채팅 서버로 부터 받은 메세지
String msg =input.readUTF();
if (msg != null){
// 핸들러에게 전달할 메세지 객체
Message hdmg = msgHandler.obtainMessage();
// 핸들러에게 전달할 메세지의 식별자
hdmg.what = 1111;
// 메세지의 본문
hdmg.obj = msg;
// 핸들러에게 메세지 전달 ( 화면 처리 )
msgHandler.sendMessage(hdmg);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
'Android' 카테고리의 다른 글
리사이클러뷰 마지막 아이템 위치로 스크롤 하기 (0) | 2018.06.05 |
---|---|
안드로이드 - PC 소캣통신 유튜브 동영상 (0) | 2018.06.03 |
이미지 원형으로 만들기 CircleImageView (0) | 2018.06.01 |
textView 글자가 많아지면 ... 으로 표기하기 (0) | 2018.05.31 |
EditText 키보드 내리기 (0) | 2018.05.25 |