参考自博客:https://blog.csdn.net/zzp_403184692/article/details/8065016
1.了解Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。建立网络通信连接至少要一对端口号(Socket)。Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。Socket通常用来实现客户端和服务端的连接,一个Socket由一个IP地址和一个端口号唯一确定。但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
2.Socket通信的过程
服务端Listen(监听)某个端口是否有连接请求,客户端向服务端发出Connect(连接)请求,服务端向客户端发回Accept(接受)消息。一个连接就建立起来了。服务端和客户端都可以通过Send,Write等方法与对方通信。对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
①创建Socket; ②打开连接到Socket的输入/出流; ③按照一定的协议对Socket进行读/写操作;④关闭Socket。
3.下面是一个服务器与单个客户端Socket通信的实例
服务端程序:
import java.io.*; import java.net.*; public class SocketServer{ public static void main(String args[]) { try{ ServerSocket server=null; try{ server=new ServerSocket(4700);//创建一个ServerSocket在端口4700监听客户请求 }catch(Exception e) { System.out.println("can not listen to:"+e); } Socket socket=null; try{ socket=server.accept();//使用accept()阻塞等待客户请求,有客户请求到来则产生一个Socket对象,并继续执行 }catch(Exception e) { System.out.println("Error."+e);//出错,打印出错信息 } String line; BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket对象得到输入流,并构造相应的BufferedReader对象 PrintWriter os=new PrintWriter(socket.getOutputStream()); //由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); //由系统标准输入设备构造BufferedReader对象 System.out.println("Client:"+is.readLine()); //在标准输出上打印从客户端读入的字符串 line=sin.readLine(); //从标准输入读入一字符串 while(!line.equals("finish")){ os.println(line);//向客户端输出该字符串 os.flush();//刷新输出流,使Client马上收到该字符串 System.out.println("Server:"+line);//在系统标准输出上打印读入的字符串 System.out.println("Client:"+is.readLine());//从Client读入一字符串,并打印到标准输出上 line=sin.readLine();//从系统标准输入读入一字符串 }//继续循环 os.close(); //关闭Socket输出流 is.close(); //关闭Socket输入流 socket.close(); //关闭Socket server.close(); //关闭ServerSocket }catch(Exception e){ System.out.println("Error:"+e); } } }客户端程序:
import java.io.*; import java.net.*; public class SocketClient { public static void main(String args[]) { try{ Socket socket=new Socket("127.0.0.1",4820);//向本机的4820端口发出客户请求 BufferedReader sin=new BufferedReader(new InputStreamReader(System.in)); //由系统标准输入设备构造BufferedReader对象 PrintWriter os=new PrintWriter(socket.getOutputStream()); //由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket对象得到输入流,并构造相应的BufferedReader对象 String readline; readline=sin.readLine(); //从系统标准输入读入一字符串 while(!readline.equals("finish")){ os.println(readline);//将从系统标准输入读入的字符串输出到Server os.flush();//刷新输出流,使Server马上收到该字符串 System.out.println("Client:"+readline);//在系统标准输出上打印读入的字符串 System.out.println("Server:"+is.readLine());//从Server读入一字符串,并打印到标准输出上 readline=sin.readLine(); //从系统标准输入读入一字符串 } os.close(); //关闭Socket输出流 is.close(); //关闭Socket输入流 socket.close(); //关闭Socket }catch(Exception e) { System.out.println("Error."+e); } } }4.下面是一个服务器与多个客户端Socket通信的实例
应用多线程来实现服务器与多线程之间的通信的基本步骤:
服务器端创建ServerSocket,循环调用accept()等待客户端链接客户端创建一个Socket并请求和服务器端链接服务器端接受客户端请求,创建socekt与该客户端建立专线链接建立链接的socket在一个单独的线程上对话服务器继续等待新的链接服务端程序:
①Server.java
import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try { //1、创建一个ServerSocket, 指定绑定的端口,并监听此端口 ServerSocket serverSocket = new ServerSocket(4820); Socket socket = null; int count = 0;//记录客户端的数量 System.out.println("即将启动,等待客户端的链接..."); while (true){//循环监听等待客户端的链接 socket = serverSocket.accept();//调用accept()方法开始监听,等待客户端的链接 ServerThread serverThread = new ServerThread(socket);//创建一个新的线程 serverThread.start();//启动线程 count++; //统计客户端的数量 System.out.println("客户端的数量: " + count); InetAddress address = socket.getInetAddress(); System.out.println("当前客户端的IP : " + address.getHostAddress()); } } catch (IOException e) { e.printStackTrace(); } } }②ServerThread.java
import java.io.*; import java.net.Socket; public class ServerThread extends Thread { Socket socket = null; public ServerThread(Socket socket){ this.socket = socket; } public void run(){//线程执行的操作,响应客户端的请求 InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; OutputStream os = null; PrintWriter pw = null; try { //获取一个输入流,并读取客户端的信息 is = socket.getInputStream(); isr = new InputStreamReader(is); //将字节流转化为字符流 br = new BufferedReader(isr); //添加缓冲 String info = null; //循环读取数据 while ((info = br.readLine()) != null){ System.out.println("我是服务器,客户端说: " +info); } socket.shutdownInput(); //关闭输入流 //获取输出流,响应客户端的请求 os = socket.getOutputStream(); pw = new PrintWriter(os); //包装为打印流 pw.write("欢迎你"); pw.flush(); //将缓存输出 } catch (IOException e) { e.printStackTrace(); }finally { try { if (pw != null) pw.close(); if (os != null) os.close(); if (is != null) is.close(); if (isr != null) isr.close(); if (br != null) br.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } 客户端程序:Client.java
import java.io.*; import java.net.Socket; public class Client { public static void main(String[] args) { try { //1、创建客户端Socket,指定服务器端口号和地址 Socket socket = new Socket("127.0.0.1",4820); //2、获取输出流,向服务器发送信息 OutputStream os = socket.getOutputStream(); //字节输出流 PrintWriter pw = new PrintWriter(os); //将输出流包装为打印流 pw.write("用户名:xxx; 密码:123456"); pw.flush(); socket.shutdownOutput(); //关闭输出流 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String info = null; //循环读取 while ((info = br.readLine()) != null){ System.out.println("我是客户端:服务器说:" + info); } br.close(); is.close(); isr.close(); pw.close(); os.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }