网络编程一对一、群聊(socket、io、线程、匿名内部类)

一、网络编程实现客户端与服务端一对一聊天:

package cn.socket.day24;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *客户端
 *理解:从键盘输入程序,通过缓冲流按行读取,同时写进数据处理流(负责发送)
 */
public class ClientDemo {
	private static final String IP = "192.168.1.8";//ip地址
	private static final int PORT = 9527;//端口
	private BufferedReader br;
	private DataOutputStream dos;
	private Socket socket;
	private DataInputStream dis;
	
		public void StartClient(){
		try {
			socket = new Socket(IP,PORT);//发起请求,打开socket连接
			/**
			 * 写
			 */
			OutputStream os = socket.getOutputStream();//获得输出流、返回此套接字的输出流。
			dos = new DataOutputStream(os);//转换成数据处理流,负责发送数据
			/**
			 * 读
			 */
			InputStream is = socket.getInputStream();
			dis = new DataInputStream(is);
			/**
			 * 获取键盘输入
			 */
			InputStreamReader isr = new InputStreamReader(System.in);
			br = new BufferedReader(isr);
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
		/**
		 * 发送信息:在这里用到br、dos、socket报错,应将对应流(类)定义为全局变量
		 * 理解:从键盘输入内容按行读到程序,再写进输出流(数据处理流),输出流负责发送
		 */
	public void sendMessage() {
		
		try {
			String s = br.readLine();
			while (!s.equals("*")) {
//				System.out.println("请输入内容开始传输:");
				s = br.readLine();// 从键盘读到程序,缓冲流按行读
				dos.writeUTF(s);// 从缓冲流读到程序,再写进输出流
			}	
		} catch (IOException e) {
			e.printStackTrace();
		}
			try {
				if(dos!=null)
				dos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	}
	/**
	 * 接收信息:
	 * 理解:服务端输出流到输出信息流,客户端输入流通过信息流读取
	 * 
	 */
	public void receiveMessage(){
		boolean flag = true;
		while(flag){
			try {
				String message = dis.readUTF();
				if(message != null)//if判断句,当只有一句话时,可以省略大括号
				System.out.println("服务端:"+message);
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("回复服务端:");
		}
		try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		public static void main(String[] args) {
			ClientDemo cd = new ClientDemo();
			cd.StartClient();
			/**
			 * 匿名内部类、线程
			 */
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					cd.receiveMessage();
					
				}
			}).start();;
//			System.out.println("请输入任意内容准备传输:");
			cd.sendMessage();
			
	}
}

package cn.socket.day24;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {

	private static final int PORT = 9527;
	private Socket socket;
	private DataOutputStream dos;
	private BufferedReader br;
	//private BufferedReader socketReader;
	private DataInputStream dis;
	
	/**
	 * 建立连接
	 */
	public void startServer(){
		System.out.println("服务器启动:");
		//DataInputStream dis = null;
		try {
			ServerSocket serverSocket = new ServerSocket(PORT);//创建绑定到特定端口的服务器套接字。
			System.out.println("开始监听!");
			socket = serverSocket.accept();// 监听|侦听并接受到此套接字的连接。
			System.out.println("连接成功!");
			/**
			 * 读
			 */
			InputStream is = socket.getInputStream();// 获得输入流、返回此套接字的输入流。
//			InputStreamReader isr1 = new InputStreamReader(is);
//			socketReader= new BufferedReader(isr1);
			dis = new DataInputStream(is);// 数据处理流、接收信息
			/**
			 * 写
			 */
			OutputStream os = socket.getOutputStream();
			dos = new DataOutputStream(os);
			/**
			 * 获取键盘输入
			 */
			InputStreamReader isr = new InputStreamReader(System.in);
			br = new BufferedReader(isr);
			
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	/**	
	 * 接收信息:
	 * 客户端从键盘输入内容按行读到程序,再写进输出流(数据处理流),输出流负责发送到信息流。服务端通过输入流在信息流内读取
	 */
	public void Receive(){
		
		boolean flag = true;//如不定义布尔值,socket只能在循环能关闭
		while(flag){
			try {
				String message = dis.readUTF();
				if(message != null)
				System.out.println("客户端:"+message);
				//System.out.println("请输入任意内容准备回复客户端:");
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
//		try {
//			socket.close();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
	}
	/**
	 * 发送消息
	 */
	public void sendMssage(){
		try {
			String message = br.readLine();
			while(!message.equals("#")){
//				System.out.println("请回复客户端:");
				message = br.readLine();
				dos.writeUTF(message);
				//socket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**	服务器启动:
		开始监听!
		连接成功!
		客户端:你好
		开始
		你好呀
		客户端:谢谢
		启动服务端开始监听—>阻塞等待客户端启动-->客户端启动连接成功
		客户端和服务端第一次发消息时,需要任意内容后在键入内容才开始正式
	 */
		public static void main(String[] args) {
			ServerDemo sd = new ServerDemo();
			sd.startServer();
			new Thread(new Runnable() {
				
				@Override
				public void run() {
//					System.out.println("请输入任意内容准备回复客户端:");
					sd.Receive();
					
				}
			}).start();
			sd.sendMssage();
	}
}

一、1.2:

package cn.socket.chat.day25;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class CilentDemo {
	private static final String IP = "192.168.1.8";
	private static final int PORT = 9528;
	private Socket socket;
	private PrintWriter socketWriter;
	private BufferedReader keyboardReader; 
	private BufferedReader socketReader;
	
	public void startClient(){
		try {
			socket = new Socket(IP,PORT);//发起socket请求,
			/**
			 * 写
			 */
//			OutputStream os = socket.getOutputStream();//返回此套接字的输出流。
//			socketWriter = new PrintWriter(os);//通过现有的 OutputStream 创建新的 PrintWriter。
			socketWriter = new PrintWriter(socket.getOutputStream());
			/**
			 * 读
			 */
//			InputStream is = socket.getInputStream();//返回此套接字的输入流。
//			InputStreamReader isr = new InputStreamReader(is);
//			socketReader = new BufferedReader(isr);
			socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			/**
			 * 获取键盘输入
			 */
//			InputStreamReader isr1 = new InputStreamReader(System.in);
//			keyboardReader = new BufferedReader(isr1);
			keyboardReader = new BufferedReader(new InputStreamReader(System.in));
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		
	/**
	 * 发送消息,在这里需要用到socketWriter和keyboardReader。所以需要将上面对应流定义为全局变量
	 */
	public void sendMessage(){
		System.out.println("输入向服务端发送的聊天内容1:");
		String message;
		try {
			message = keyboardReader.readLine();
			while(!message.equals("exit")){
				socketWriter.println(message);
				socketWriter.flush();//刷新该流的缓冲。
				message = keyboardReader.readLine();
//				System.out.println("输入聊天内容:");
			}
			
		} catch (IOException e) {
			System.out.println("结束聊天2!");
//			e.printStackTrace();
		}
		socketWriter.close();
	}
	
	/**
	 * 接收消息:在这里需要用到socketReader,所以需要将上面对应流定义为全局变量
	 */
	public void ReceiveMessage() {
		boolean isStop = true;
		while (isStop) {
			try {
				String message = socketReader.readLine();
				if(message != null){
					System.out.println("服务端:"+message);
				}
			} catch (IOException e) {
				System.out.println("结束聊天!");
//				e.printStackTrace();
			}
			System.out.println("回复服务端:");
		}
		
		try {
			socket.close();//关闭流
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**控制台:	
	 *  输入向服务端发送的聊天内容1:
		你好,我是客户端
		服务端:好的
		回复服务端:
		。
		服务端:0
		回复服务端:
	 */
	public static void main(String[] args) {
		final CilentDemo cd = new CilentDemo();
		cd.startClient();
		/**
		 * 匿名内部类
		 */
		new Thread(new Runnable() {

			@Override
			public void run() {
				cd.ReceiveMessage();//在内部类访问(ReceiveMessage();)方法时需要加final。或者CilentDemo cd定义为全局变量
			}
		}).start();
		cd.sendMessage();
	}
}

package cn.socket.chat.day25;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *服务端
 *第一步:建立连接
 *	1.实例化ServerSocket
 *  2.监听端口有无连接请求
 *  
 *第二步:接收信息实质是从socket输入流中读取数据
 *      发送信息实质是向socket输出流写数据
 */
public class ServerDemo {
	private static final int PORT = 9528;//端口号
	private BufferedReader socketReader;
	private Socket socket;
	private PrintWriter socketWriter;
	private BufferedReader keyBoardReader;
	
	/**
	 * 建立连接
	 */
	public void startSever(){
		try {
			ServerSocket serverSocket = new ServerSocket(PORT);//创建绑定到特定端口的服务器套接字。
			System.out.println("开始监听");
			socket = serverSocket.accept();//监听|侦听并接受到此套接字的连接。
			System.out.println("建立连接成功!");
			
			socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//接收信息
			socketWriter = new PrintWriter(socket.getOutputStream());//发送信息
			keyBoardReader = new BufferedReader(new InputStreamReader(System.in));//从键盘读数据
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 接收信息:
	 *子线程
	 */
	public void receiveMessage(){
		new Thread(new Runnable(){

			@Override
			public void run() {
				boolean isStop = true;
				while(isStop){
					try {
						String message = socketReader.readLine();
						if(message != null){
							System.out.println("客户端:"+message);
							System.out.println("请回复客户端:");
						}
					} catch (IOException e) {
						isStop = false;
						e.printStackTrace();
					}
				}
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}).start();
	}
	
	/**
	 * 发送信息:
	 * 主线程
	 */
	public void sendMessage(){
		try {
			
			String message = keyBoardReader.readLine();
			while(!message.equals("exit")){
				//System.out.println("请输入向客户端发送的内容:");
				socketWriter.println(message);
				socketWriter.flush();//刷新
				message = keyBoardReader.readLine();
			}
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**控制台:当启动服务端,服务端控制台显示:开始监听。当启动客户端,服务端控制台显示:建立连接成功!
	 * 	开始监听
		建立连接成功!
		客户端:你好,我是客户端
		请回复客户端:
		好的
		客户端:。
		请回复客户端:
		0
	 */
	public static void main(String[] args){
		ServerDemo sd = new ServerDemo();
		sd.startSever();
		sd.receiveMessage();
		sd.sendMessage();
	}
}

二、实现多人聊天:

package cn.socket.multiuserchats.day26;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *客户端
 *理解:从键盘输入程序,通过缓冲流按行读取,同时写进数据处理流(负责发送)
 */
public class ClientDemo {
	private static final String IP = "192.168.5.41";//ip地址
	private static final int PORT = 9527;//端口
	private BufferedReader br;
	private DataOutputStream dos;
	private Socket socket;
	private DataInputStream dis;
	private PrintWriter pw;
	private BufferedReader br1;
	
		public void StartClient(){
		try {
			socket = new Socket(IP,PORT);//发起请求,打开socket连接
			/**
			 * 写
			 */
			OutputStream os = socket.getOutputStream();//获得输出流、返回此套接字的输出流。
			pw = new PrintWriter(os);
			//dos = new DataOutputStream(os);//转换成数据处理流,负责发送数据
			/**
			 * 读
			 */
			InputStream is = socket.getInputStream();
			br1 = new BufferedReader(new InputStreamReader(is));
			//dis = new DataInputStream(is);
			/**
			 * 获取键盘输入
			 */
			InputStreamReader isr = new InputStreamReader(System.in);
			br = new BufferedReader(isr);
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
		/**
		 * 发送信息:在这里用到br、dos、socket报错,应将对应流(类)定义为全局变量
		 * 理解:从键盘输入内容按行读到程序,再写进输出流(数据处理流),输出流负责发送
		 */
	public void sendMessage() {
		System.out.println("请输入任意内容准备传输:");
		try {
			String s = br.readLine();
			while (!s.equals("*")) {
				System.out.println("请输入内容开始传输:");
				s = br.readLine();// 从键盘读到程序,缓冲流按行读
				//dos.writeUTF(s);// 从数据流读到程序,再写进输出流
				pw.println(s);//此处用BufferedWriter写不到服务端
				pw.flush();
			}	
		} catch (IOException e) {
			e.printStackTrace();
		}
//			try {
//				if(dos!=null)
//				dos.close();
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
	}
	/**
	 * 接收信息:
	 * 理解:服务端输出流到输出信息流,客户端输入流通过信息流读取
	 * 
	 */
	public void receiveMessage(){
		boolean flag = true;
		while(flag){
			try {
				//String message = dis.readUTF();
				String message = br1.readLine();
				if(message != null)//if判断句,当只有一句话时,可以省略大括号
				System.out.println("服务端:"+message);
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("回复服务端:");
		}
		try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		public static void main(String[] args) {
			final ClientDemo cd = new ClientDemo();
			cd.StartClient();
			/**
			 * 匿名内部类、线程
			 */
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					cd.receiveMessage();
					
				}
			}).start();;
			cd.sendMessage();
	}
}

package cn.socket.multiuserchats.day26;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class MulThread {
	private static final int PORT = 9527;
	private ArrayList lists = new ArrayList();
	private BufferedReader br;
	
	
	public void startServer(){
		try {
			System.out.println("服务端启动!");
			ServerSocket serverSocket = new ServerSocket(PORT);
			
//			br = new BufferedReader(new InputStreamReader(System.in));
//			sendAllMessageThreadBykeyboard();
			new SendMessage(lists);
			
			while(true){
			Socket socket = serverSocket.accept();//监听
			lists.add(socket);
			System.out.println("已成功连接:"+lists.size());
			
			new ReceiveThread(socket,lists);
			
		
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 群发线程:方式一:匿名内部类    方式二:SendMessage线程实现Runablb
	 * @param args
	
	public void sendAllMessageThreadBykeyboard(){
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					String message = br.readLine();
					while(!message.equals("exit")){
						sendAllMessage(message);
						message = br.readLine();
					}
					
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
		}).start();
	
	}
	
	public void sendAllMessage(String message) throws IOException{
		if(lists.size() ==0){
			return;
		}
		for(Socket socket : lists){
			PrintWriter pw = new PrintWriter(socket.getOutputStream());
			pw.println(message);
			pw.flush();
		}
	}
	/**
	 * 	服务端启动!
		已成功连接:1
		客户端:x bnsxnsbxsjx
		客户端:xhaXBAJajxbx
		客户端:xaxhjxaxhjXHkHXKxxAXKJaKLxja
		客户端:sbxSBXsxsbxSB
		客户端:xnKXNAxaxnKXN
		客户端:xkNXaknxkx
		已成功连接:2
	 * @param args
	 */
	public static void main(String[] args) {
		MulThread mt = new MulThread();
		mt.startServer();

	}

}

package cn.socket.multiuserchats.day26;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

public class ReceiveThread implements Runnable{
	private Socket socket;
	private ArrayList socketlist;
	private BufferedReader br;
	
	public ReceiveThread(Socket socket,ArrayList lists) throws IOException{
		this.socket = socket;
		this.socketlist = lists;
		this.br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		Thread t = new Thread(this);
		t.start();
	}
	
	@Override
	public void run() {
		ReceiveMessage();
		
	}
	/**
	 * 接收客户端发送的信息
	 * @throws IOException
	 */
	public void ReceiveMessage(){
		boolean flag = true;
		while(flag){
			try {
				String message = br.readLine();
				if(message != null){
					System.out.println("客户端:"+message);
					changeAllMessage(message);
				}
			} catch (IOException e) {
				flag = false;
			}
			
		}
	}
	
	/**
	 * 转发接收到的信息到已连接客户端
	 * @throws IOException 
	 */
	public void changeAllMessage(String message) throws IOException{
		for(Socket socket : socketlist){
			if(this.socket == socket){
				continue;
			}
			PrintWriter pw = new PrintWriter(socket.getOutputStream());
			pw.println(message);
			pw.flush();
		}	
	}
}

package cn.socket.multiuserchats.day26;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

public class SendMessage implements Runnable{
	private ArrayList arrayList;
	private Socket socket;
	
	public SendMessage(ArrayList lists){
		this.arrayList = lists;
		this.socket = socket;
		new Thread(this).start();
	}
	@Override
	public void run() {
		/**
		 * 键盘写入缓冲流,缓冲流读出来的内容,再写到scoket  控制台:
		 * 	服务端启动!
			已成功连接:1
			客户端:dawdwdwa
			qq
			客户端:ddwadwa
		 */
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		try {
			String message = br.readLine();
			while(!message.equals("exit")){
				if(arrayList.size() != 0){
					for(Socket socket : arrayList){
						PrintWriter pw = new PrintWriter(socket.getOutputStream());
						pw.println(message);//写
						pw.flush();//刷新
					}
				}
				message = br.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

小结:

网络编程: 

1. C/S   Client/Server    客户端/服务端模式   --->网络套接字实现

连接过程: 服务端:监听对应端口连接        客户端:根据ip、端口号发起socket请求

类似电话: 被叫方:监听来电                        主叫方:根据电话号码打电话

2.B/S     Brower/Server   浏览器/服务器模式

URL统一资源定位符    作用:表示网络中资源

格式:协议://ip地址/域名/主机名、端口号/路径/文件

http://192.168.5.4:80/webapp/index.html


你可能感兴趣的:(网络(socket,io,线程)的综合使用)