TCP协议(Socket,ServerSocket)

TCP协议

  • 传输控制协议(Transmission Control Protocol)
  • TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务器发出连接请求,每次连接的创建都需要经过“三次握手

三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠

  • 第1次握手,客户端向服务器发出连接请求,等待服务器确认
  • 第2次握手,服务器向客户端回送一个响应,通知客户端收到了连接请求
  • 第3次握手,客户端再次向服务器发送确认信息,确认连接

完成三次握手,建立连接后,客户端和服务器就可以开始进行数据传输了。由于这种面相连接的特性,TCP协议可以保证 数据传输的安全,所以应用十分广泛。例如上传文件,下载文件,浏览网页等。

废话少说,直接放客户端的代码

package com.wangLuo;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * @author 林高禄
 * @create 2020-06-01-10:24
 */
public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.1.55",10);
        OutputStream os = s.getOutputStream();
        byte[] bys = "TCP客户端写入数据,好好学习,努力提升!".getBytes();
        os.write(bys);
        s.close();
    }
}

运行报一下错

Exception in thread "main" java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.connect0(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at java.net.Socket.connect(Socket.java:538)
    at java.net.Socket.(Socket.java:434)
    at java.net.Socket.(Socket.java:211)
    at com.wangLuo.TCPClient.main(TCPClient.java:13)

这是因为我们还没有接收端,接收端还没有运行,因为TCP协议是要先建立连接,再发送数据

下面就直接放接收端的代码

package com.wangLuo;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author 林高禄
 * @create 2020-06-01-10:28
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10);
        Socket s = ss.accept();
        InputStream is = s.getInputStream();
        byte[] bys = new byte[3];
        int len;
        while((len = is.read(bys)) != -1){
            System.out.print(new String(bys,0,len));
        }
        ss.close();
    }
}

接收启动接收端,再启动发送端,接收端输出:

TCP客户端写入数据,好好学习,努力提升!

了解了TCP协议后,我们改进一下,服务器做出反馈,让客户端知道,客户端也接收服务端的反馈

客户代码

package com.wangLuo;

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

/**
 * @author 林高禄
 * @create 2020-06-01-10:24
 */
public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.1.55",10);
        OutputStream os = s.getOutputStream();
        byte[] bys = "TCP客户端写入数据,好好学习,努力提升!".getBytes();
        os.write(bys);
        InputStream is = s.getInputStream();
        byte[] bys1 = new byte[1024];
        int len = is.read(bys1);
        System.out.println(new String(bys1,0,len));
        s.close();
    }
}

服务端代码

package com.wangLuo;

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

/**
 * @author 林高禄
 * @create 2020-06-01-10:28
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10);
        Socket s = ss.accept();
        InputStream is = s.getInputStream();
        byte[] bys = new byte[3];
        int len;
        while((len = is.read(bys)) != -1){
            System.out.print(new String(bys,0,len));
        }
        System.out.println();
        System.out.println("sss");
        OutputStream os = s.getOutputStream();
        os.write("数据已收到".getBytes());
        ss.close();
    }
}

启动服务端,在启动客户端,我们发现客户端和服务端的程序并没有停止,并且服务端的“sss”并没有输出,说明服务端的代码一直没有往下执行,所以一直没有给客户端反馈,导致客户端也一直在等待服务端的反馈

TCP协议(Socket,ServerSocket)_第1张图片

这是因为我们服务端接收客户端的方式是while循环,服务器并不知道客户端何时输入完毕,所以一直在等待,这就需要客户端给服务端一个标记,让服务端知道客户端何时发送完毕,我们可以让客户端发送某些字符作为标记,然后服务端做判断,当接收到的字符是这些字符,就会结束while循环,但是这样做会有bug,就是当我们实际要发送的数据如果包含这些字符,那么传输就不完整,因为会导致服务端结束循环,往后的内容就接收不到。

别急,Java的Socket类提供了自带的标记方法,shutdownOutput(),客户端调用这个方法,向服务端表明发送数据完毕,那么我们的客户端的代码就改进一下,加多这个方法

package com.wangLuo;

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

/**
 * @author 林高禄
 * @create 2020-06-01-10:24
 */
public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.1.55",10);
        OutputStream os = s.getOutputStream();
        byte[] bys = "TCP客户端写入数据,好好学习,努力提升!".getBytes();
        os.write(bys);
        // 向服务端表明数据发送完毕
        s.shutdownOutput();
        InputStream is = s.getInputStream();
        byte[] bys1 = new byte[1024];
        int len = is.read(bys1);
        System.out.println(new String(bys1,0,len));
        s.close();
    }
}

启动服务端,在启动客户端,2个程序都走完停止

服务端输出:

TCP客户端写入数据,好好学习,努力提升!
sss

客户端输出:

数据已收到

TCP协议我们基本了解了,那就做一个练习,TCP多线程 实现文件上传。

你可能感兴趣的:(java基础)