基于TCP的Socket通信

基于TCP的Socket通信

TCP提供基于“流”的“长连接”的数据传递,发送的数据带有顺序性。

TCP是一种流协议,以流为单位进行数据传输。

  • 短连接: 短连接是当服务端与客户端连接成功后开始传输数据,数据传输完毕后则连接立即关闭,如果还想再次传输数据,则需要再创建新的连接进行数据传输。
  • 长连接: 长连接可以实现当服务端与客户端连接成功后连续地传输数据,在这个过程中,连接保持开启的状态,数据传输完毕后连接不关闭。长连接是指建立Socket连接后,无论是否使用这个连接,该连接都保持连接的状态。
  • 连接: 在TCP/IP中,连接可以认为是服务端与客户端确认彼此都存在的过程。这个过程需要实现,就要创建连接,如何创建连接(环境)呢?需要服务端与客户端进行3次握手,握手成功之后,说明服务端与客户端之间能实现数据通信。如果建立连接的过程是成功的,就说明连接被成功创建。在创建好的1个连接中,使用TCP可以实现多次的数据通信。在多次数据通信的过程中,服务端与客户端要进行彼此都存在的过程验证,也就是验证连接是否正常,如果连接正常,并且多次通信,则这就是长连接。长连接就是复用当前的连接以达到数据多次通信的目的。由于复用当前的连接进行数据通信,因此不需要重复创建连接,传输效率比较高。而当实现1次数据通信之后,关闭连接,这种情况就可称为短连接。使用短连接进行数据传输时,由于每次传输数据前都要创建连接,这样会产生多个连接对象,增大占用内存的空间,在创建连接时也要进行服务端与客户端之间确认彼此存在,确认的过程比较耗时,因此运行效率较低。由于UDP是无连接协议,也就是服务端与客户端没有确认彼此都存在的握手过程,因此在UDP里面不存在长连接与短连接的概念

长连接的优缺点:

  • 优点:除了第一次之外,客户端不需要每次传输数据时都先与服务端进行握手,这样就减少了握手确认的时间,直接传输数据,提高程序运行效率。
  • 缺点:在服务端保存多个Socket对象,大量占用服务器资源。

短连接的优缺点:

  1. 优点:在服务端不需要保存多个Socket对象,降低内存占用率。
  2. 缺点:每次传输数据前都要重新创建连接,也就是每次都要进行3次握手,增加处理的时间。
验证ServerSocket类的accept()方法具有阻塞特性

ServerSocket类的作用是创建Socket (套接字)的服务端,而Socket类的作用是创建Socket的客户端。在代码层面使用的方式就是使用Socket类去连接ServerSocket类,也就是客户端要主动连接服务端。

ServerSocket类中的public Socket accept() 方法的作用是侦听并接受此套接字的连接。此方法在连接传人之前一直阻塞。public Socket accept()方法的返回值是Socket类型。
在本实验中,将验证ServerSocket类中的accept()方法具有阻塞特性,也就是当没有客户端连接服务端时,呈阻塞状态。

try {
            ServerSocket socket = new ServerSocket(8088);
            System.out.println("server阻塞开始=" + System.currentTimeMillis());
            socket.accept();
            System.out.println("server阻塞结束=" + System.currentTimeMillis());
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

因为没有客户端,所以服务端就会一直阻塞。

//客户端
public static void main(String[] args) {
        Socket socket = null;
        try {
            socket = new Socket("localhost", 8088);
            System.out.println("socket连接成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行客户端,一旦连接到服务端,阻塞变结束。

构造方法public Socket(String host, int port)第一个参数host可以是IP,也可以是域名。
如果host参数不存在,则会抛出UnknowHostException异常。

验证Socket中InputStream类的read()方法也具有阻塞特性
public static void main(String[] args) {
        try {
            byte[] byteArray = new byte[1024];
            ServerSocket serverSocket = new ServerSocket(8088);
            System.out.println("accept begin " + System.currentTimeMillis());
            Socket socket = serverSocket.accept();//阻塞效果
            System.out.println("accept end " + System.currentTimeMillis());

            InputStream inputStream = socket.getInputStream();
            System.out.println("read begin " + System.currentTimeMillis());
            int readLength = inputStream.read(byteArray);//阻塞效果
            System.out.println("read end " + System.currentTimeMillis());
            inputStream.close();
            socket.close();;
            serverSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


public static void main(String[] args) {
        try {
            System.out.println("Socket begin " + System.currentTimeMillis());
            Socket socket = new Socket("localhost", 8088);
            System.out.println("Socket end " + System.currentTimeMillis());
            Thread.sleep(Integer.MAX_VALUE);
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

服务端输出:

accept begin 1591542927764
accept end 1591542929700
read begin 1591542929701

在read()处阻塞的原因是客户端并未发送数据到服务端,服务端会一直尝试读取从客户端传递过来的数据,尾音客户端从未发送数据给服务端,所以服务端一直在阻塞。

客户端向服务端传递字符串
public static void main(String[] args) {
        try {
            char[] charArray = new char[3];
            ServerSocket serverSocket = new ServerSocket(8088);
            Socket socket = serverSocket.accept();

            InputStream inputStream = socket.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            int readLength = inputStreamReader.read(charArray);
            while (-1 != readLength) {
                String str = new String(charArray, 0, readLength);
                System.out.println(str);
                readLength = inputStreamReader.read(charArray);
            }
            inputStreamReader.close();
            inputStream.close();
            socket.close();
            serverSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8088);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("向服务端传送的数据".getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

服务端输出:

向服务
端传送
的数据
服务端向客户端传递字符串
public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8088);
            Socket socket = serverSocket.accept();
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("服务端向客户端发送消息".getBytes());
            outputStream.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8088);
            char[] charBuffer = new char[3];
            InputStream inputStream = socket.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            int readLength = inputStreamReader.read(charBuffer);
            while (-1 != readLength) {
                System.out.println(new String(charBuffer, 0, readLength));
                readLength = inputStreamReader.read(charBuffer);
            }
            inputStreamReader.close();
            inputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

客户端输出:

服务端
向客户
端发送
消息
实现服务端与客户端多次的往来通信
public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8088);
            Socket socket = serverSocket.accept();

            //输入开始
            InputStream inputStream = socket.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            int byteLength = objectInputStream.readInt();
            byte[] byteArray = new byte[byteLength];
            objectInputStream.readFully(byteArray);
            String str = new String(byteArray);
            System.out.println(str);
            //输入结束

            //输出开始
            OutputStream outputStream = socket.getOutputStream();
            String strA = "客户端你好A\n";
            String strB = "客户端你好B\n";
            String strC = "客户端你好C\n";

            int allStrByteLength = (strA + strB + strC).getBytes().length;

            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeInt(allStrByteLength);
            objectOutputStream.flush();

            objectOutputStream.write(strA.getBytes());
            objectOutputStream.write(strB.getBytes());
            objectOutputStream.write(strC.getBytes());
            objectOutputStream.flush();
            //输出结束

            //输入开始
            byteLength = objectInputStream.readInt();
            byteArray = new byte[byteLength];
            objectInputStream.readFully(byteArray);
            str = new String(byteArray);
            System.out.println(str);
            //输入结束

            //输出开始
            outputStream = socket.getOutputStream();
            String strD = "客户端你好D\n";
            String strE = "客户端你好E\n";
            String strF = "客户端你好F\n";

            allStrByteLength = (strD + strE + strF).getBytes().length;

            objectOutputStream.writeInt(allStrByteLength);
            objectOutputStream.flush();

            objectOutputStream.write(strD.getBytes());
            objectOutputStream.write(strE.getBytes());
            objectOutputStream.write(strF.getBytes());
            objectOutputStream.flush();
            //输出结束

            inputStream.close();
            socket.close();
            serverSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }



public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8088);
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            //输出开始
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            String strA = "服务端你好A\n";
            String strB = "服务端你好B\n";
            String strC = "服务端你好C\n";

            int allStrByteLength = (strA + strB + strC).getBytes().length;

            objectOutputStream.writeInt(allStrByteLength);
            objectOutputStream.flush();

            objectOutputStream.write(strA.getBytes());
            objectOutputStream.write(strB.getBytes());
            objectOutputStream.write(strC.getBytes());
            objectOutputStream.flush();
            //输出结束

            //输入开始
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            int byteLength = objectInputStream.readInt();
            byte[] byteArray = new byte[byteLength];
            objectInputStream.readFully(byteArray);
            String str = new String(byteArray);
            System.out.println(str);
            //输入结束

            //输出开始
            String strD = "服务端你好D\n";
            String strE = "服务端你好E\n";
            String strF = "服务端你好F\n";
            allStrByteLength = (strD + strE + strF).getBytes().length;
            objectOutputStream.writeInt(allStrByteLength);
            objectOutputStream.flush();
            objectOutputStream.write(strD.getBytes());
            objectOutputStream.write(strE.getBytes());
            objectOutputStream.write(strF.getBytes());
            objectOutputStream.flush();
            //输出结束

            //输入开始
            byteLength = objectInputStream.readInt();
            byteArray = new byte[byteLength];
            objectInputStream.readFully(byteArray);
            str = new String(byteArray);
            System.out.println(str);
            //输入结束

            objectOutputStream.close();
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

客户端输出:

客户端你好A
客户端你好B
客户端你好C

客户端你好D
客户端你好E
客户端你好F

服务端输出:

服务端你好A
服务端你好B
服务端你好C

服务端你好D
服务端你好E
服务端你好F

注意:Stream 在Socket技术中进行应用时,如果关闭返回的Stream,将关闭关联的Socket (套接字),类型为InputStream的对象inputStream的真正数据类型是java.net.SocketInputStream。

当调用java.net.SocketInputStream类的close()方法时,顺便也将Socket(套接字)close()关闭。如果Socket关闭,则服务端与客户端不能进行通信。

集合多线程实现通信
public class Server4113 {
    public static void main(String[] args) {
        try {
            Executor pool = Executors.newFixedThreadPool(10);
            ServerSocket serverSocket = new ServerSocket(8888);
            for (;;) {
                Socket socket = serverSocket.accept();
                pool.execute(new ReadRunnable(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class ReadRunnable implements Runnable {

    private Socket socket;

    public ReadRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            byte[] byteArray = new byte[100];
            int readLength = inputStream.read(byteArray);
            while (readLength != -1) {
                System.out.println(new String(byteArray, 0, readLength));
                readLength = inputStream.read(byteArray);
            }
            inputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class Client4113 {
    public static void main(String[]args) {
        try {
            Socket socket = new Socket("localhost", 8888);
            OutputStream outputStream = socket.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            outputStreamWriter.write("客户端发送消息...");
            outputStreamWriter.flush();
            Thread.sleep(Integer.MAX_VALUE);
            outputStreamWriter.close();
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

注意:

  1. 服务端先获得 ObjectInputStream对象,客户端就要先获得 ObjectOutputStream对象;
  2. 服务端先获得 ObjectOutputStream对象,客户端就要先获得 ObjectInputStream对象。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值