通信原理:客户端发数据,服务端接收;服务端发数据,客户端接收。在客户端和服务端有一条通道,运用输入输出流收发数据。
设计如下:
(1)发数据的线程: Sender
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Sender implements Runnable {
private DataOutputStream dos;
public Sender (Socket socket,String userName){
try {
this.dos = new DataOutputStream(socket.getOutputStream());
//发送用户名到服务器
this.dos.writeUTF(userName);
this.dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
send();
}
}
public void send(){ //发数据
BufferedReader console = null;
try {
console = new BufferedReader(new InputStreamReader(System.in));
String data = console.readLine();
dos.writeUTF(data);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)收数据的线程:Receiver
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receiver implements Runnable {
private DataInputStream dis ;
public Receiver(Socket socket){
try {
this.dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
receiver();
}
}
public void receiver(){
String data = null;
try {
data = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(data);
}
}
(3)服务端
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 {
//保存正在服务的客服对象
public static List<CustomerServer> customerServers = new ArrayList<CustomerServer>();
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8888);
//设定QQServer程序的端口号为8888
while (true){
//循环一次,获取一个新的通道Socket
Socket socket = serverSocket.accept();
System.out.println("一个客户端进来......");
//有一个客户端进来,分配一个客服为其服务
//客服多线程运行
CustomerServer customerServer = new CustomerServer(socket);
//添加客服
customerServers.add(customerServer);
Thread t = new Thread(customerServer);
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//内部类
private static class CustomerServer implements Runnable{
private String userName; //服务的用户名
private DataInputStream dis;
private DataOutputStream dos;
public CustomerServer(Socket socket){
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
//接收用户名消息
this.userName = dis.readUTF();
//发系统消息 给自己
send(userName +"成功登陆");
//发给他人系统消息
otherSend("热列欢迎尊贵的心悦Ⅲ---" + userName +"---进入群聊室");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
//接收消息
String msg = receive();
//转发消息
otherSend( msg);
}
}
private String receive(){
try {
return dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}return "没有";
}
private void send (String mag){
try {
dos.writeUTF(mag);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void otherSend (String mag){
if (mag.startsWith("@") && mag.contains(":") && mag.indexOf(":") - mag.indexOf("@") >= 2){ //私聊的条件 @姓名:内容
//名称
String name = mag.substring(1,mag.indexOf(":"));
//内容
String content = mag.substring(mag.indexOf(":")+1);
//遍历集合
Iterator<CustomerServer> it = customerServers.iterator();
while (it.hasNext()) {
CustomerServer customerServer = it.next();
if (name.equals(customerServer.userName)) {//相同名字
customerServer.send(this.userName + "悄悄地对你说:" + content);
break;
}
}
}else{//群发 遍历集合
Iterator<CustomerServer> it = customerServers.iterator();
while (it.hasNext()){
CustomerServer customerServer = it.next();
if (customerServer != this){
customerServer.send(userName + "对大家说:" + mag);
}
}
}
}
}
}
(4)客户端
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class QQClient {
public static void main(String[] args) {
Scanner input = new Scanner(System.in); //改动
System.out.print("请输入用户名: ");
String userName = input.next();
Socket socket = null;
try {
socket = new Socket(InetAddress.getByName("localhost"),8888);
//启动线程
new Thread(new Receiver(socket)).start();
new Thread(new Sender(socket,userName)).start(); //改动
} catch (IOException e) {
e.printStackTrace();
}
}
}
(5)测试
Ⅰ、先运行服务端,在运行客户端。
Ⅱ、创建三个用户
Ⅲ、群聊
Ⅳ、私聊