package socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Server {
/*
* 运行在服务端的ServerSocket
* 有两个主要作用:
* 1:向系统申请对外的服务端口,客户端就是通过
* 这个端口与服务端建立连接的.
* 2:监听服务端口,等待客户端连接.一旦一个客户端
* 通过Socket与服务端建立连接,那么ServerSocket
* 会创建一个Socket与该客户端通讯.
*/
private ServerSocket server;
/*
* 该数组用于存放所有客户端的输出流
*/
// private PrintWriter[] allOut = new PrintWriter[0];
private List<PrintWriter> allOut
= new ArrayList<PrintWriter>();
public Server(){
try {
/*
* 创建ServerSocket的同时向系统申请
* 对外的服务端口.注意,该端口不能和
* 其他程序冲突,否则会抛出地址被占用
* 的异常.
*/
server = new ServerSocket(8088);
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
try {
/*
* ServerSocket提供方法:
* Socket accept()
* 该方法是一个阻塞方法,调用后即等待
* 客户端的连接,一旦一个客户端通过
* 端口连接,那么accept方法会返回一个
* Socket实例,通过这个Socket实例就
* 可以与刚连接的客户端交互了
*/
while(true){
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("一个客户端连接了!");
//启动一个线程,处理该客户端交互工作
ClientHandler handler
= new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/**
* 该线程任务负责与指定Socket所对应的客户端
* 进行交互.
* @author adminitartor
*
*/
private class ClientHandler
implements Runnable{
//当前线程通过这个Socket与对应客户端交互
private Socket socket;
/**
* 实例化时将对应客户端的Socket传入
* @param socket
*/
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run(){
PrintWriter pw = null;
try {
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(
in,"UTF-8"
)
);
/*
* 获取输出流,用于给当前客户端回复消息
*/
pw = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream(),
"UTF-8"
)
),true
);
//将当前客户端对应的输出流存入共享数组
synchronized (allOut) {
// //1扩容数组
// allOut = Arrays.copyOf(allOut, allOut.length+1);
// //2将输出流存入数组
// allOut[allOut.length-1] = pw;
allOut.add(pw);
}
/*
* 客户端在断开连接时不同系统有不同反应
* linux的客户端断开后,br.readLine方法会
* 返回null.
* windows的客户端断开连接后,br.readLine方法
* 会直接抛出异常.
*/
String message = null;
while((message = br.readLine())!=null){
System.out.println("客户端说:"+message);
//回复客户端
// pw.println("客户端说:"+message);
//发送给所有客户端
synchronized (allOut) {
// for(int i=0;i<allOut.length;i++){
// allOut[i].println("客户端说:"+message);
// }
for(PrintWriter o : allOut){
o.println("客户端说:"+message);
}
}
}
} catch (Exception e) {
} finally{
//处理客户端断开连接后的操作
//1将该客户端的输出流从共享数组中删除
synchronized (allOut) {
// for(int i=0;i<allOut.length;i++){
// if(allOut[i]==pw){
// //将最后一个元素放入当前位置
// allOut[i] = allOut[allOut.length-1];
// //缩容
// allOut = Arrays.copyOf(allOut, allOut.length-1);
// break;
// }
// }
allOut.remove(pw);
}
/*
* 2客户端断开连接后,服务端关闭
* 该客户端Socket,释放资源
*/
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class Client {
/*
* java.net.Socket
* 套接字,封装了TCP协议.Socket提供了两条流
* 用来与服务端进行双向通讯.
*/
private Socket socket;
/**
* 构造方法,用来初始化客户端
*/
public Client(){
try {
/*
* 实例化Socket就是连接服务端的过程
* 参数1:服务端地址
* 参数2:服务端开启的服务端口
*
* 通过服务端IP地址可以找到服务端所处
* 计算机,再通过端口找到运行在服务端
* 计算机上的服务端应用程序.
*/
socket = new Socket("localhost",8088);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 客户端开始工作的方法
*/
public void start(){
try {
//先启动线程接收服务端发送的消息
ServerHandler handler = new ServerHandler();
Thread t = new Thread(handler);
t.start();
Scanner scanner = new Scanner(System.in);
/*
* Socket提供方法:
* OutputStream getOutputStream()
* 通过返回的字节输出流写出的数据会发送
* 给远端计算机,对于客户端这边而言远端
* 计算机就是服务端了.
*/
OutputStream out
= socket.getOutputStream();
PrintWriter pw = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
out,"UTF-8"
)
),true
);
while(true){
String line = scanner.nextLine();
pw.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
/**
* 该线程负责循环接收服务端发送过来的消息.
* 给服务端发送消息与接收服务端发过来的消息
* 要放在两个不同的线程要运行,这样才能做到
* 互相不干扰.
* @author adminitartor
*
*/
private class ServerHandler
implements Runnable{
public void run(){
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(
socket.getInputStream(),
"UTF-8"
)
);
String message = null;
while((message = br.readLine())!=null){
System.out.println(message);
}
} catch (Exception e) {
}
}
}
}