TCP通信

TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。

两端通信时步骤:

  1. 服务端程序,需要事先启动,等待客户端的连接。
  2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。

在Java中,提供了两个类用于实现TCP通信程序:

  1. 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
  2. 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。

常用命令

  • 查看本机IP地址,在控制台输入:
ipconfig
  • 检查网络是否连通,在控制台输入:
ping 空格 IP地址
ping 220.181.57.216

特殊的IP地址

  • 本机IP地址:127.0.0.1localhost

端口号:用两个字节表示的整数,它的取值范围是0—65535 。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。

Socket

Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。

构造方法
public Socket(String host, int port)    创建套接字对象并将其连接到指定主机上的指定端口号。
										如果指定的host是null ,则相当于指定地址为回送地址。  
例:
Socket client = new Socket("127.0.0.1", 2000);

成员方法
public InputStream getInputStream() 	返回此套接字的输入流。
										如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
										关闭生成的InputStream也将关闭相关的Socket。
										
public OutputStream getOutputStream() 	返回此套接字的输出流。
										如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
										关闭生成的OutputStream也将关闭相关的Socket。
										
public void close()						关闭此套接字。
										一旦一个socket被关闭,它不可再使用。
 										关闭此socket也将关闭相关的InputStream和OutputStream 。 
 										
public void shutdownOutput()			禁用此套接字的输出流。   
										任何先前写出的数据将被发送,随后终止输出流。 

ServerSocket

构造方法
public ServerSocket(int port)  			使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上
										参数port就是端口号。
例:
ServerSocket server = new ServerSocket(2000);

成员方法
public Socket accept()					侦听并接受连接,返回一个新的Socket对象
										用于和客户端实现通信。该方法会一直阻塞直到建立连接。 									

文件上传优化分析

  1. 文件名称写死的问题

服务端,保存文件的名称如果写死,那么最终导致服务器硬盘,只会保留一个文件。
建议使用系统时间优化,保证文件名称唯一,代码如下:

FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名称
BufferedOutputStream bos = new BufferedOutputStream(fis);
  1. 循环接收的问题

    服务端,指保存一个文件就关闭了,之后的用户无法再上传,这是不符合实际的。
    使用循环改进,可以不断的接收不同用户的文件,代码如下:

// 每次接收新的连接,创建一个Socket
whiletrue{
    Socket accept = serverSocket.accept();
    ......
}
  1. 效率问题

    服务端,在接收大文件时,可能耗费几秒钟的时间,此时不能接收其他用户上传,所以,使用多线程技术优化,代码如下:

whiletrue{
    Socket accept = serverSocket.accept();
    // accept 交给子线程处理.
    new Thread(() -> {
      	......
        InputStream bis = accept.getInputStream();
      	......
    }).start();
}

例1:简单通信

服务器端
public static void main(String[] args) {

        try (
                //创建服务器对象
                ServerSocket server = new ServerSocket(2000);

                ){
            //接受客户端对象
            Socket accept = server.accept();
            //获取输入流对象
            InputStream is = accept.getInputStream();
            byte[] bytes = new byte[1024];
            int len;

            while ((len = is.read(bytes))!= -1){
                String msg = new String(bytes, 0, len);
                System.out.println(msg);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
客户端
public static void main(String[] args) {

        try(
                //获取Socket对象
                Socket socket = new Socket("127.0.0.1", 2000);

                ) {
            OutputStream os = socket.getOutputStream();
            os.write("nihao".getBytes());


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

例 2 :文件传输

服务器
 public static void main(String[] args) {

        try (
                //创建服务器对象
                ServerSocket server = new ServerSocket(2000);
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"))

                ){
            //接受客户端对象
            Socket accept = server.accept();
            //获取输入流对象
            InputStream is = accept.getInputStream();
            byte[] bytes = new byte[1024];
            int len;

            while ((len = is.read(bytes))!= -1){
               bos.write(bytes,0,len);

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

客户端
public static void main(String[] args) {

        try(
                //创建输入流对象,读取本地文件
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream("钻二.png"));
                //获取Socket对象
                Socket socket = new Socket("127.0.0.1", 2000);
                //创建输出流对象,将文件上传到服务器
                BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

                ) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes))!= -1){
                bos.write(bytes,0,len);
                bos.flush();
            }
            System.out.println("文件放完毕");
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("文件已上传");
    }

例 3 :优化后的文件传输

服务器
 public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(2000);

        while (true) {
            //接受客户端对象
            Socket accept = server.accept();
            new Thread(()->{
                try (
                        FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                        BufferedOutputStream bos = new BufferedOutputStream(fos);
                ) {
                    //获取输入流对象
                    InputStream is = accept.getInputStream();
                    byte[] bytes = new byte[1024];
                    int len;

                    while ((len = is.read(bytes)) != -1) {
                        bos.write(bytes, 0, len);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

        }
    }

客户端代码不变。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值