底層使用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();
}
}