socket使用TCP/IP协议来实现网络进程之间的通信,socket是TCP/IP的封装与应用,它不是协议,而是API。

实现目标:

①实现一个客户端与一个服务器之间的通信

②实现多个客户端与服务器之间的通信

③实现将用户的信息转发给所有的客户端

Client客户端:

package ChatRoom;

import java.io.BufferedReader;
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;
import java.util.Scanner;

/**
 * 聊天室的客户端
 *  1.完成连接服务器
 *  2.给服务器发送信息或请求
 */
public class Client {
	//Socket里封装了TCP协议 
	private Socket socket;//设置属性私有化

	//设置构造器用来初始化:与类同名没有返回值
	public Client() throws UnknownHostException, IOException{
		/*
		 * 实例化Socket的过程就是连接远端计算机的过程
		 * new Socket(访问的IP,服务器的端口号);
		 * 过程,这里需要传入两个参数
		 * 参数1:服务端的IP地址信息
		 * 参数2:服务端的端口
		 * 通过IP可以找到服务端的计算机,
		 * 通过端口可以连接到运行在服务端计算机上的服务端应用程序。
		 */
		System.out.println("正在连接服务器.....");
		socket=new Socket("localhost",8088);
		System.out.println("已经连接成功服务器");
	}
	
	//创建客户端工作方法:
	public void start(){
		//1.实现客户端向服务器端发送请求/信息的功能
		//输出
		try {
			//发信息给服务器
			OutputStream out=socket.getOutputStream();
			//设置编码格式(UTF-8   GBK)  说明我们设置的流
			OutputStreamWriter osw=new OutputStreamWriter(out,"utf-8");
			//设置输出格式:
			PrintWriter pw=new PrintWriter(osw,true);
			//正式输出:`
			pw.println("你好,服务器");
			Scanner scan=new Scanner(System.in);
			while(true){
				pw.println(scan.nextLine());
				if(scan.nextLine() == "over") {
					break;
				}
			}
			//如果需要接受服务器的信息先关闭资源socket.shutdownOutput()
			//然后写从服务器接收到的信息类似于客户端接受服务器信息一样
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			//必须执行
		}
	}
	
	
	public static void main(String[] args) {
		try {
			Client c=new Client();
			c.start();
		} catch (UnknownHostException e) {
			System.out.println(1);
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println(2);
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

Server服务器端:

package ChatRoom;

import java.io.BufferedReader;
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.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 聊天室的服务器端
 *   1.设置端口号
 *   2.接收客户端发送的信息或要求
 */
public class Server {
	private static final String ClientHandler = null;
	/*
	 * 运行在服务端ServerSocket两个作用:
	 * 1:申请服务端口,客户端就是通过该端口 
	 *   与服务端建立连接的
	 * 2:监听申请的服务端口,一旦一个客户端
	 *   通过该端口与服务端连接,ServerSocket
	 *   就会主动创建一个Socket与该客户端通讯
	 */
	private ServerSocket server;
	//储存客户端所有数据:
	List<PrintWriter> list;
	
   //创建构造器用来初始化server:
	public Server() throws IOException{
		/*
		 * 初始化ServerSocket的同时,指定
		 * 要申请的服务端口,若该端口已经
		 * 被其他程序占用,会抛出异常。
		 */
		//server=new ServerSocket("你要申请的端口号");
		server=new ServerSocket(8088);
		list=new ArrayList<PrintWriter>();
	}
	
	//聊天开始的方法:用于接收客户端发送消息
	public void start() throws IOException{
		/* 监听端口,等待客户端连接
		 * ServerSocket的accept方法
		 * 是一个阻塞方法,作用是监听
		 * 服务端口,直到一个客户端通过
		 * 该端口连接,才会返回一个Socket
		 * 实例,通过这个Socket可以与刚
		 * 连接的客户端通讯。
		 * accept:接收客户的连接及请求
		 */
		System.out.println("等待客户端连接...");
		Socket socket=server.accept();
		//调用线程类-----处理客户端发送来的信息
		//1.创建对象:
		ServerHandle handle=new ServerHandle(socket);
		
		//调用------启动一个线程完成对该客户端的交互:
		new Thread(handle).start();//这个就由你们自己测试了,可以用朋友的电脑也连接这个服务器进行测试
		
		System.out.println("连接一个客户端");
		//接受客户端
		InputStream in = socket.getInputStream();
		InputStreamReader isr = new InputStreamReader(in,"UTF-8");
		BufferedReader br = new BufferedReader(isr);
		System.out.println("客户端说:"+br.readLine());
		while (true) {
			System.out.println("客户端说:"+br.readLine());
			if(br.readLine() == "over") {
				break;
			}
		}
		//如果需要发信息给客户端先关闭资源socket.shutdownOutput()
		//类似于客户端发信息给服务器端一样
		
	}
	
	
	public static void main(String[] args) {
		//创建一个Server对象:
		try {
			Server s=new Server();
			s.start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//创建一个内部类:定义输出流,数组用来存储用户发送的信息
	//因为集合问题(list)无法再其他类中被调用,所以无法实现向集合中添加用户传入的信息
	//所以在Server里再声明一个内部类
	  
	private class ClientHandler implements Runnable{
		private Socket socket;
		public ClientHandler(Socket socket){
			this.socket=socket;
		}
		@Override
		public void run() {
			PrintWriter pw=null;
			try {
				OutputStream out=socket.getOutputStream();
				//设置编码格式(UTF-8   GBK)  说明我们设置的流
				OutputStreamWriter osw=new OutputStreamWriter(out,"utf-8");
				//设置输出格式:
				pw=new PrintWriter(osw);
				list.add(pw);
				
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
		}
		
	}

}


//创建线程-----处理各个客户端的请求
class ServerHandle extends Thread{
	private Socket socket;
	//初始化:
	public ServerHandle(Socket socket) throws IOException{
		this.socket=socket;
		//将参数赋值给本类对象
	}
	@Override
	public void run() {
		//接收用户信息:
				InputStream in;
				try {
					in = socket.getInputStream();
					//设置接收的流的编码格式
					InputStreamReader isr=new InputStreamReader(in,"UTF-8");
					//设置接收,将用户输出流转换
					BufferedReader br=new BufferedReader(isr);
					//将接收的内容输出到控制台中  readLine:读取一行
					while(true){
						System.out.println("客户端说:"+br.readLine());  
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
	}
}