要想详细了解socket,大家请自行百度,我这里只简单介绍。

  在网络中,我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。而socket编程就是为了完成两个唯一进程之间的通信(一个是客户端,一个是服务器端),其中用到的协议是TCP/UDP协议,它们都属于传输层的协议。

  TCP是基于连接的协议,在收发数据前,需要建立可靠的连接,也就是所谓的三次握手。使用TCP协议时,数据会准确到达,但是效率较低。

  UDP是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去。使用UDP协议时,传输效率高,但是不能保证数据准确到达,视频聊天,语音聊天时就用的UDP协议。

  以使用TCP协议通讯的socket为例,其交互流程大概是这样子的:

              服务器端              客户端

           创建服务器端的socket        创建客户端的socket

           绑定端口号             连接服务器端的端口

           监听端口              向服务器端发送数据

           接收客户端的连接请求        关闭socket

           读取客户端发送数据

           关闭socket

 

  下面贴上代码:

  服务器端:

package SocketStudy;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(10068);//创建绑定到特定端口的服务器Socket。
            Socket socket = null;//需要接收的客户端Socket
            int count = 0;//记录客户端数量
            System.out.println("服务器启动");
            //定义一个死循环,不停的接收客户端连接
            while (true) {
                socket = serverSocket.accept();//侦听并接受到此套接字的连接
                InetAddress inetAddress=socket.getInetAddress();//获取客户端的连接
                ServerThread thread=new ServerThread(socket,inetAddress);//自己创建的线程类
                thread.start();//启动线程
                count++;//如果正确建立连接
                System.out.println("客户端数量:" + count);//打印客户端数量
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

 

 自定义线程类:

package SocketStudy;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class ServerThread extends Thread {
    Socket socket = null;
    InetAddress inetAddress=null;//接收客户端的连接

    public ServerThread(Socket socket,InetAddress inetAddress) {
        this.socket = socket;
        this.inetAddress=inetAddress;
    }

    @Override
    public void run() {
        InputStream inputStream = null;//字节输入流
        InputStreamReader inputStreamReader = null;//将一个字节流中的字节解码成字符
        BufferedReader bufferedReader = null;//为输入流添加缓冲
        OutputStream outputStream = null;//字节输出流
        OutputStreamWriter writer = null;//将写入的字符编码成字节后写入一个字节流
        try {
            inputStream = socket.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String info = null;//临时

            //循环读取客户端信息
            while ((info = bufferedReader.readLine()) != null) {
                //获取客户端的ip地址及发送数据
                System.out.println("服务器端接收:"+"{'from_client':'"+socket.getInetAddress().getHostAddress()+"','data':'"+info+"'}");
            }

            socket.shutdownInput();//关闭输入流

            //响应客户端请求
            outputStream = socket.getOutputStream();
            writer = new OutputStreamWriter(outputStream, "UTF-8");
            writer.write("{'to_client':'"+inetAddress.getHostAddress()+"','data':'我是服务器数据'}");
            writer.flush();//清空缓冲区数据
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            try {
                if (writer != null) {
                    writer.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

客户端:

package SocketStudy;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class SocketClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("服务器的ip", 10068);
            OutputStream outputStream = socket.getOutputStream();//得到一个输出流,用于向服务器发送数据
            OutputStreamWriter writer=new OutputStreamWriter(outputStream,"UTF-8");//将写入的字符编码成字节后写入一个字节流
            System.out.println("请输入数据:");
            Scanner sc = new Scanner(System.in);
            String data = sc.nextLine();
            writer.write(data);
            writer.flush();//刷新缓冲
            socket.shutdownOutput();//只关闭输出流而不关闭连接
            //获取服务器端的响应数据

            InputStream inputStream = socket.getInputStream();//得到一个输入流,用于接收服务器响应的数据
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");//将一个字节流中的字节解码成字符
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//为输入流添加缓冲
            String info = null;

       System.out.println("客户端IP地址:"+socket.getInetAddress().getHostAddress());
//输出服务器端响应数据
            while ((info = bufferedReader.readLine()) != null) {
                System.out.println("客户端接收:" + info);
            }
            //关闭资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            writer.close();
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

运行结果(先运行服务器端,再运行客户端):

服务器:

java模拟多个客户端连接 redis集群 java多客户端通信_客户端

 客户端:

 

java模拟多个客户端连接 redis集群 java多客户端通信_服务器端_02

回车之后

客户端:

 

java模拟多个客户端连接 redis集群 java多客户端通信_java_03

 

服务器端:

 

java模拟多个客户端连接 redis集群 java多客户端通信_客户端_04

 

在cmd下运行(先编译再运行生成的.class文件,如果有中文,需要加encoding参数,当类中有导入自己创建的类时,需要切换到能包含该类的文件夹下执行命令,否则会报错)

java模拟多个客户端连接 redis集群 java多客户端通信_服务器端_05

此时的服务器端:

java模拟多个客户端连接 redis集群 java多客户端通信_java_06