天天看點

Socket程式設計實作簡易的聊天室

底層使用TCP/IP ,點對點通信,保證資料不會被丢失

JAVA對通信程式設計做了支援,類庫在net裡面。

1.發送資料的線程

package com.csdn.servet;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
 * 發送資料的線程
 * @author Administrator
 *
 */
public class Sender implements Runnable{
	private boolean flag = true;
	private DataOutputStream dos;
	private BufferedReader br;
	private String userName;
	public Sender(Socket socket,String userName){
		try {
			dos = new DataOutputStream(socket.getOutputStream());
			br = new BufferedReader(new InputStreamReader(System.in));
			this.userName = userName;
			//發送資訊到服務端
			send(userName);
			
		} catch (IOException e) {
			e.printStackTrace();
			this.flag = false;
		}
	}
	
	@Override
	public void run() {
		try{
			while(flag){
				//從控制台接收一個字元串
//			String msg = getMsg();
				//發送出去
				send(getMsg());
			}
		}finally{
			if(null != br){
				try {
					br.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(null != dos){
				try {
					dos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	private String getMsg(){
		try {
			return br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
			this.flag = false;
			return "";
		}
	}
	
	private void send(String msg){
		if(null != msg && !"".equals(msg.trim())){
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				e.printStackTrace();
				this.flag = false;
			}
		}
	}

	public String getUserName() {
		return userName;
	}
	
	
}

           

2.接收資料的線程

package com.csdn.servet;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 接收資料線程
 * @author Administrator
 *
 */
public class Reciever implements Runnable{
//	private Socket socket;
	private DataInputStream dis;
	
	private boolean flag = true;//辨別位

	public Reciever(Socket socket) {
		super();
//		this.socket = socket;
		try {
			dis = new DataInputStream(socket.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
			this.flag = false;
		}
	}


	@Override
	public void run() {
		try{
			while(flag){
				//接收資料
				System.out.println(receive());
			}
		}finally{
			if(null != dis){
				try {
					dis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	private String receive(){
		try {
			return dis.readUTF();
		} catch (IOException e) {
			e.printStackTrace();
			this.flag = false;
			return "";
		}
	}

}

           

3.服務端代碼:

package com.csdn.servet;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class QQServer {
	private static List<CustomService>  onlineList = new ArrayList<CustomService>();
	
	public static void main(String[] args) throws Exception{
		ServerSocket serverSocket = null;
		serverSocket = new ServerSocket(9527);//整數  1024以下不要使用
		while(true){
			Socket socket = serverSocket.accept();//一直處于監聽狀态,
			System.out.println("有一個用戶端進來");
			//來一個用戶端,就會有一個新的Socket産生
			//委派一個客服為其服務
			CustomService customService = new CustomService(socket);
			
			onlineList.add(customService);//追加到線上清單
			new Thread(customService).start();
		}
	
	}
	
	//CustomService就當做是客服
	private static class CustomService implements Runnable{
		private boolean flag = true;
		
		private DataInputStream dis;
		private DataOutputStream dos;
		private String userName;
		public CustomService(Socket socket){
			try {
				dis = new DataInputStream(socket.getInputStream());
				dos = new DataOutputStream(socket.getOutputStream());
				//記錄用戶端的姓名
				this.userName = dis.readUTF();
				//給你自己發送一條系統資訊
				dos.writeUTF("系統消息,歡迎" + this.userName + "登陸聊天室");
				//給其他人也推送一條系統資訊
				sendOthersSysInfo("系統消息,熱烈歡迎" + this.userName + "來到QQ聊天室");
			} catch (IOException e) {
				e.printStackTrace();
				this.flag = false;
			}
		}
		
		/**
		 * 發送一條系統資訊
		 * @param msg
		 */
		private void sendOthersSysInfo(String msg){
			Iterator<CustomService> it = onlineList.iterator();
			while(it.hasNext()){
				CustomService customService = it.next();
				if(customService == this){//自己
					continue;
				}
				customService.send(msg);
			}
		}
		
		@Override
		public void run() {
			try{
				String msg = "";
				while(flag){
					msg = receive(); 
					//判斷到底是私聊還是直接群聊  私聊的格式@使用者名:内容
					if(msg.startsWith("@") && msg.indexOf(":") > 1){//私聊
						sendSecret(msg);
					}else{//群聊
						sendOthers(this.getUserName() + "對大家說:" + msg);
					}
				}
			}finally{
				if(null != dos){
					try {
						dos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if(null != dis){
					try {
						dis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		private String receive(){
			try {
				return dis.readUTF();
			} catch (IOException e) {
				e.printStackTrace();
				this.flag = false;
				return  "";
			}
		}
		private void sendSecret(String msg){
			String secretName = msg.substring(1,msg.indexOf(":"));
			msg = msg.substring(msg.indexOf(":") + 1);
			Iterator<CustomService> it = onlineList.iterator();
			while(it.hasNext()){
				CustomService customService = it.next();
				if(secretName.equals(customService.getUserName())){
					customService.send(this.getUserName() + "使用者悄悄地對你說:" + msg);
					break;
				}
			}
			
		}
		
		private void sendOthers(String msg){
			//轉發操作
			Iterator<CustomService> it = onlineList.iterator();
			while(it.hasNext()){
				CustomService customService = it.next();
				if(customService == this){
					continue;
				}
				customService.send(msg);
			}
		}
		
		private void send(String msg){

			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				this.flag = false;
				
			}
		}
		public String getUserName() {
			return userName;
		}	
	}
}


           

4.用戶端代碼

package com.csdn.client;

import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

import com.csdn.servet.Reciever;
import com.csdn.servet.Sender;

public class QQClient {
	public static void main(String[] args)throws Exception {
		Scanner input = new Scanner(System.in);
		System.out.print("請輸入使用者名:");
		String userName = input.next();
		//連接配接服務端
		Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9527);
		
		//登陸成功後,需要将使用者名資訊立刻發送到伺服器
		
		//啟動收資料線程
		Reciever reciever = new Reciever(socket);
		//啟動發資料線程
		Sender sender = new Sender(socket,userName);
		new Thread(reciever).start();
		new Thread(sender).start();
	}
}

           

繼續閱讀