JAVA之旅(三十三)——TCP传输,互相(伤害)传输,复制文件,上传图片,多并发上传,多并发登录

JAVA之旅(三十三)——TCP传输,互相(伤害)传输,复制文件,上传图片,多并发上传,多并发登录


我们继续网络编程

一.TCP

说完UDP,我们就来说下我们应该重点掌握的TCP了

  • TCP传输
    • Socket和ServiceSocket
    • 建立客户端和服务端
    • 建立连接后,通过Socket中的IO流进行数据的传输
    • 关闭Socket

同样的,我们的客户端和服务端都是两个独立的应用

我们通过查阅API文档发现,该对象在建立的时候,就可以去连接指定主机,因为tcp是面向连接的,所以在建立socket服务时,就要有服务存在,并成功连接,形成通路后,在该通道进行数据传输

所以我们用代码来看下他的步骤

客户端

package com.lgl.hellojava;

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

public class TcpClient {

    public static void main(String[] args) {
        try {
            //1.创建客户端的服务,传地址和端口
            Socket s = new Socket("192.168.1.102",10000);
            //2.为了发送数据,应该获得socket流中的输出流
            OutputStream out = s.getOutputStream();
            out.write("你好".getBytes());
            s.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

服务端

package com.lgl.hellojava;

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

/**
 * 定义端点接收数据打印出来
 * 服务端:
 * 1.建立服务端的socket服务,servicesocket,并监听一个端口
 * 2.获取连接过来的客户端对象,通过accept方法,这个方法是阻塞的,没有连接就会等
 * 3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该对象的读取流
 * 4.关闭服务端(可选操作)
 * @author LGL
 *
 */
public class TcpService {
    public static void main(String[] args) {
        try {
            //1.建立连接,监听端口
            ServerSocket ss = new ServerSocket(10000);
            //2.连接客户端对象
            Socket accept = ss.accept();
            //获取ip
            String ip = accept.getInetAddress().getHostAddress();
            //3.获取客户端发送过来的数据
            InputStream in = accept.getInputStream();
            //4.开始读取
            byte [] buf = new byte[1024];
            int len = in.read(buf);
            System.out.println(new String(buf,0,len));
            //5.关闭
            ss.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

二.TCP互相传输

我们在来写一个实例去说明,他们的互访动作,这里为了写起来方便,就写在一个类中了

package com.lgl.hellojava;

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

/**
 * 客户端发送信息,服务端收到,反馈信息
 *
 * @author LGL
 *
 */
public class Tcp {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("192.168.1.102", 10005);
            OutputStream out = s.getOutputStream();
            out.write("我是客户端".getBytes());
            InputStream in = s.getInputStream();
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            System.out.println(new String(buf, 0, len));
            s.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
/**
 * 服务端
 * @author LGL
 *
 */
class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10005);
            Socket s = ss.accept();
            InputStream in = s.getInputStream();
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            System.out.println(new String(buf, 0, len));

            OutputStream out = s.getOutputStream();
            out.write("收到后反馈".getBytes());
            s.close();
            ss.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

三.复制文件

同样的这里也是使用的流,我们具体来看下怎么去操作,我们同样的,写在一个类中

package com.lgl.socket;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class FileClient {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("192.168.1.102", 10006);
            BufferedReader bufr = new BufferedReader(new FileReader("test.txt"));
            PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
            String line = null;
            while ((line = bufr.readLine()) != null) {
                pw.println(line);
            }
            pw.print("over");
            BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            String str = bufIn.readLine();
            System.out.println(str);

            bufr.close();
            s.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class FileServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10006);
            Socket s = ss.accept();

            BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            PrintWriter out = new PrintWriter(new FileWriter("test1.txt"), true);
            String line = null;
            while ((line = bufIn.readLine()) != null) {
                if ("over".equals(line))
                    break;
                out.println(line);
            }
            PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
            pw.println("上传成功");

            out.close();
            s.close();
            ss.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

四.上传图片

我们再来看下图片是怎么上传的,我们先来分析下步骤

客户端

  • 1.服务端点
  • 2.读取客户端已有的图片数据
  • 3.通过socket,发送给服务端
  • 4.读取服务端反馈的信息
  • 5.关闭资源
**
 * 客户端
 *
 * @author LGL
 *
 */
public class PicClient {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("192.168.1.102", 10009);
            FileInputStream fis = new FileInputStream("1.png");
            OutputStream out = s.getOutputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            //告訴服务端数据写完
            s.shutdownInput();
            InputStream in = s.getInputStream();
            byte[] bufn = new byte[1024];
            int num = in.read(bufn);
            System.out.println(new String(bufn, 0, num));
            fis.close();
            s.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

服务端

直接看代码


/**
 * 服務端
 * @author LGL
 *
 */
class PicServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10009);
            Socket s = ss.accept();
            InputStream in = s.getInputStream();
            FileOutputStream fos = new FileOutputStream("2.png");
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = in.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }

            OutputStream out = s.getOutputStream();
            out.write("上传成功".getBytes());
            fos.close();
            s.close();
            ss.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

其实跟I/O区别真不大,但是概念一定要了解清楚

五.多并发上传

多并发这个概念就是多人互动了,这对服务器的负荷还是有考究的,这里呢,我们就模拟一下,多人上传图片的场景,我们是怎么做的?我们还是在上传图片的那份代码上更改

首先我们可以确定的是,这是服务端的代码

  • 这个服务端有个局限性,当A客户端连接之后,被服务端获取到,服务端就在执行代码了,这个时候如果B客户端连接只有等待,这就是我们需要多并发的原因了,为了让多个客户端同时连接,服务端最好就是讲每个客户端封装到一个单独的线程中,这样就可以同时处理多个客户端请求

如何定义线程?

  • 只要明确了每个客户端要在服务端执行的代码即可

/**
 * 服務端
 *
 * @author LGL
 *
 */
class PicServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10009);
            while (true) {
                Socket s = ss.accept();
                new Thread(new PicThread(s)).start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
/**
 * 并发线程
 * @author LGL
 *
 */
class PicThread implements Runnable {

    private Socket s;

    public PicThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            String ip = s.getInetAddress().getHostAddress();
            System.out.println("ip:" + ip);

            long millis = System.currentTimeMillis();
            File file = new File(millis + ".png");
            InputStream in = s.getInputStream();
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = in.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }

            OutputStream out = s.getOutputStream();
            out.write("上传成功".getBytes());
            fos.close();
            s.close();
        } catch (Exception e) {

            throw new RuntimeException("上传失败");
        }

    }

}

其实我写的代码还是有点烂的,但是思想在就好,我们得先把思想学会了

六.多并发登录

上面说的多并发的上传,实在服务端端,现在我们来说下登录,是作用在客户端

package com.lgl.socket;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class LoginClient {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("192.168.1.102", 10008);
            BufferedReader bufr = new BufferedReader(new InputStreamReader(
                    System.in));
            PrintWriter out = new PrintWriter(s.getOutputStream(), true);
            BufferedReader bufIn = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));
            for (int i = 0; i < 3; i++) {
                String line = bufr.readLine();
                if (line == null) {
                    break;
                }
                out.println(line);

                String info = bufIn.readLine();
                System.out.println("info:" + info);
                if (info.contains("欢迎")) {
                    break;
                }
            }
            bufr.close();
            s.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * 服务端
 *
 * @author LGL
 *
 */
class LoginServer {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(10008);
            while (true) {
                Socket s = ss.accept();
                new Thread(new UserThread(s)).start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * 并发登陆
 *
 * @author LGL
 *
 */
class UserThread implements Runnable {

    private Socket s;

    public UserThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                BufferedReader bufrIn = new BufferedReader(
                        new InputStreamReader(s.getInputStream()));
                String name = bufrIn.readLine();

                // 模拟读取数据库的用户名
                BufferedReader bufr = new BufferedReader(new FileReader(
                        "user.txt"));

                PrintWriter out = new PrintWriter(s.getOutputStream(), true);

                String line = null;

                boolean flag = false;
                while ((line = bufr.readLine()) != null) {
                    if (line.equals(name)) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    System.out.println("已登录");
                    out.print("欢迎");
                } else {
                    System.out.println("重新登录");
                    out.println("用户名不存在");
                }
                s.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

}

OK,这些代码中可能会存在一些错误,因为代码并没有去实际的验证中,我写的时候也是跟着思想去走的,这样写代码是极为友好的,这就是TCP的冰山一角了,不过关于这些,还有很多知识点,我们要做的就是把思想给掌握了,万变不理其中

好的,最近写文的时间,有点懈怠了,看来要发力了,嘻嘻,

有兴趣的加群:555974449 一起来玩玩吧!

时间: 2024-11-09 00:36:58

JAVA之旅(三十三)——TCP传输,互相(伤害)传输,复制文件,上传图片,多并发上传,多并发登录的相关文章

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了,而且收到的好评也不错,于是就一直坚持了下来,非常感谢各位小伙伴哦! JAVA之旅合集 JAVA之旅(一)--基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算 JAVA之旅(二)--if,switch,for,while,do while,语句嵌套,流程

JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用

JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例,我们暂时不讲了,我们直接来重点吧,关于JAVA的网络请求是怎么实现的?当然是HTTP协议,但是不可否认,他的概念和思想都是我们必须去涉及的,包括后面的tcp和socket等,好吧,我们开车吧! 一.JAVA网络请求概述 关于JAVA的网络请求,我们大致的可以分为以下几个分类 网络模式 OSI TCP

JAVA之旅(二十三)——System,RunTime,Date,Calendar,Math的数学运算

JAVA之旅(二十三)--System,RunTime,Date,Calendar,Math的数学运算 map实在是太难写了,整理得我都晕都转向了,以后看来需要开一个专题来讲这个了,现在我们来时来学习一些新的小东西吧 一.System 翻译过来系统的意思,系统类,里面的方法都是静态的,可以直接调用 我们来演示一下吧,先从获取系统信息开始: package com.lgl.hellojava; import java.util.Properties; public class HelloJJAVA

JAVA之旅(三十四)——自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫

JAVA之旅(三十四)--自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫 我们接着来说网络编程,TCP 一.自定义服务端 我们直接写一个服务端,让本机去连接,可以看到什么样的效果 package com.lgl.socket; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; publ

JAVA之旅(三)——数组,堆栈内存结构,静态初始化,遍历,最值,选择/冒泡排序,二维数组,面向对象思想

JAVA之旅(三)--数组,堆栈内存结构,静态初始化,遍历,最值,选择/冒泡排序,二维数组,面向对象思想 我们继续JAVA之旅 一.数组 1.概念 数组就是同一种类型数据的集合,就是一个容器 数组的好处:可以自动给数组中的元素从0开始编号,方便操作这些元素 数组的格式 //公共的 类 类名 public class HelloJJAVA { // 公共的 静态 无返回值 main方法 数组 public static void main(String[] str) { /** * 格式:元素类型

JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI 一.GUI的概述 GUI全称叫做Graphical User Intergace(图形用户接口),用图形的方式,来显示计算机操作的界面,这样更加方便直观,与用户交互 说道交互,其实系统跟用户有两种交互,一种是GUI,一种叫做CLI,也就是命令行,全称叫做Command User Intergace

JAVA之旅(三十)——打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码

JAVA之旅(三十)--打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码 三十篇了,又是一个阳光明媚的周末,一个又一个的周末,周而复始,不断学习,前方的路你可曾看见?随我一起走进技术的世界,流连忘返吧! 一.打印流PrintWriter 打印流有PrintWriter和PrintStream,他的特点可以直接操作输入流还有文件 该流提供了打印方法,可以将各种数据类型原样打印 file对象

JAVA之旅(一)——基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算

JAVA之旅(一)--基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算 Android老鸟重新学一遍JAVA是什么感觉?枯燥啊,乏味啊,而且归纳写博客,都是很痛苦的事情,但是程序之路这么长,你必须精通的不能再精通一门语言才行(有点说大了哈),但是最起码你要如鱼得水吧,我准备的资料有: JAVA编程思想 深入浅出JAVA 黑马,传智,慕课,极客学院等-的视频 Google搜索 我们既然是重新学一遍,那我们尽量就是用记事本去敲代码好了,这里我用notep