Java-网络编程学习(二)--- TCP协议、Socket通信原理以及实现

TCP协议

IP协议(Internet Protocol)

  • 负责计算机之间的通信。将消息从一个主机传送到另一个主机

  • 负责在因特网上发送和接收数据包。

TCP协议(Transport Control Protocol)

  • 用于从应用程序到网络的数据传输控制。

  • 负责在数据传送之前将它们分割为 IP 包,然后在它们到达的时候将它们还原。

  • 被称作一种端对端协议,当一台计算机需要与另一台远程计算机连接时,TCP协议会让他们建立一个连接:用于发送和接收数据的虚拟链路。

  • TCP协议使用重发机制:当一个通信实体(A)发送消息给另个通信实体(B)后,需要接收到B的确认信息,如果没有收到确认信息,会再次重发刚发送的信息。

  • URL、URLConnection、Socket、ServerSocket等类都使用TCP协议进行网络通讯

Socket通信

通信原理

  • 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket
  • socket通常用来实现客户端(Client)和服务器端(Server)的连接

如下图:
在这里插入图片描述

详细:
在这里插入图片描述

解读:

  • Server端有一个ServerSocket对象用来监听来自客户端的Socket连接,如果没有连接,它一直处于等待(wait)状态。

  • 客户端发起一个请求(request)给服务端,服务端收到request之后,会通过accept()方法返回一个Socket,然后客户端和服务端就会建立起连接(connect)

    //服务器端创建一个ServerSocket来监听客户端的Socket连接请求
    ServerSocket ss = new ServerSocket(2000);
    //不断接受客户端的请求
    while(true){
        //每接受到一个客户端Socket,服务器也会对应产生一个Socket
        Socket s = ss.accept();
        //通过socket进行通讯
        ...
    }
    
  • 通过Socket对象获得对方的I/O流,进行数据的读写

  • 完成通信后,关闭Socket

代码实现

Socket类:
  • Socket()
  • Socket(InetAddress address, int port) — 创建远程连接到指定远程主机、远程端口的Socket
  • InputStream getInputStream() — 返回该Socket对象对应的输入流,程序通过该输入流从Socket中取出数据(接收来自另一方发送的信息)
  • OutputStream getOutputStream() — 返回该Socket对象对应的输出流,程序通过该输出流向Socket中输出数据(往外发东西)
ServerSocket类:
  • ServerSocket() — 用指定的端口号(0~65535)创建一个ServerSocket
  • Socket accept() — 如果接收到一个客户端Socket的连接请求,返回一个与客户端Socket对应的Socket,否则该方法一直处于等待状态,线程也被阻塞。
客户端Socket的建立
/*
* 第一个参数 host 是目标服务器的地址,"127.0.0.1"通常指的是本机地址,
* 我们自己在写程序的时候,只有一台电脑,我们的电脑同时启动两个虚拟机,一个为服务端,
* 一个是客户端,这个时候服务端的地址就是本机地址
* 
* 第二个参数为端口号,只要在范围内并且不取1024下的保留号就可以
* 但是客户端的端口号必须和对应服务端的端口号一致
*/
try {
    Socket socket = new Socket("127.0.0.1", 2000);
} catch (IOException e) {
    System.out.println("Error:"+e);
}
服务器端Socket的建立
try {
    ServerSocket serverSocket = new ServerSocket(2000);
    Socket socket = serverSocket.accept();
} catch (IOException e) {
    System.out.println("Error:"+e);
}
构建输入输出流

方法一:

//获得输出流---往外发信息
PrintStream os = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
//获得输入流---接收来自另一方发送的信息
DataInputStream is = new DataInputStream(socket.getInputStream());

方法二:

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

/*
* InputStreamReader  转换流(字节到字符的转换)
* PrintWriter 打印输出流
* BufferedReader 缓冲流
* DataInputStream  数据操作流
*/
例:
简单的命令行聊天系统

服务器端

package com.sehun.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class ServerDemo {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = null;
            Socket socket = null;
            try {
                serverSocket = new ServerSocket(3999);
                System.out.println("Server Run !");
                socket = serverSocket.accept();
                System.out.println("客户端已连接\n");
            }catch (IOException e){
                System.out.println("连接失败");
            }

            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
            //输出流,将服务端的内容发送给客户端
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            //输入流,读取来自客户端发给它的信息
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String readLine = in.readLine();
            System.out.println("Client: "+readLine);
            String line = sin.readLine();
            while (!line.equals("over")){
                out.println(line);
                out.flush();
                readLine = in.readLine();
                if (readLine==null){
                    System.out.println("客户端已下线,请输入【over】结束本次聊天");
                }else
                    System.out.println("Client: " + readLine);
                line = sin.readLine();
            }
            out.close();
            in.close();
            socket.close();
            serverSocket.close();
        } catch (Exception e) {
            System.out.println("Error:"+e);
        }
    }
}

客户端:

package com.sehun.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

//客户端
public class ClientDemo {
    public static void main(String[] args) {
        try {
            Socket socket = null;
            try {
                socket = new Socket("127.0.0.1", 3999);
                System.out.println("Client Run!\n");
            }catch (IOException e){
                System.out.println("连接服务端失败");
            }

            //键盘输入流,获取用户从键盘输入的信息
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
            //输出流,从客户端将信息发送给服务端
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            //输入流,接收来自网络上服务端发送给本程序的信息
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = sin.readLine();
            String readLine = null;
            //用户通过“over”字符串来告诉程序是否结束
            while(!line.equals("over")){
                out.println(line);
                //强制输出数据(清空缓冲区的数据流)
                out.flush();
                readLine = in.readLine();
                if (readLine==null){
                    System.out.println("服务端已下线,请输入【over】结束本次聊天");
                }else
                    System.out.println("Server: "+readLine);
                line = sin.readLine();
            }
            out.close();
            in.close();
            socket.close();

        } catch (Exception e) {
            System.out.println("Error:"+e);
        }
    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值