JAVA-网络编程1(基础知识详解)


心得体会

  • 今天学的东西挺有趣的,从简单的服务端与客户端模拟,到实现群聊,一步一步感觉demo实现的功能越来越多。同一段的代码,不厌其烦的反复敲,与其他代码组合起来,就实现了不同的功能^^
    --

今日所学

  • 1.OSI与TCP/IP体系模型

  • 2.URL

  • 3.IP地址和端口

  • 4.TCP和UDP

  • 5.Socket

  • 6.服务器端和客户端(聊天小demo)

具体操作

1.OSI与TCP/IP体系模型

image.png

image.png

2.URL

URL的定义

URL是统一资源定位符(Uniform Resource Locator,缩写为URL),又叫做网页地址,是互联网上标准的资源的地址(Address)。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

URL的组成
PVF1_B{`M{4SFAN`04DAUJG.png

http://www.baidu.com/search?code=android

http:——指定因特网服务的类型。最流行的类型是HTTP
www.baidu.com——域名 表示一台网络中的电脑
search——URL的这部分被称为层级文件路径
code=android —— 查询字符串是一个非必须的字段,只要负责将一系列非层级格式的任意参数传给服务器。可同时传递多个参数,参数之间用“&"符号连接,每个参数名与值用 = 隔开
& ——如果有多个参数使用&符号链接 例如: www.baidu.com?uid=777&qqq=666


3.IP地址和端口号

  • 1、IP地址用于唯一标示网络中的一个通信实体。这个通信实体可以是一台主机,可以是一台打印机,或者是路由器的某一个端口。而在基于IP协议网络中传输的数据包,必须使用IP 地址来进行标示。IP地址就像写一封信,必须指定收件人的地址一样。每个被传输的数据包中都包括了一个源IP和目标IP。
  • 2、IP地址唯一标示了通信实体,但是一个通信实体可以有多个通信程序同时提供网络服务。这个时候就要通过端口来区分开具体的通信程序。一个通信实体上不能有两个通信程序,使用同一个端口号。
  • 3.IP地址和端口号,就像一个出差去外地入住酒店一样,IP地址表示了酒店在具体位置,而端口号则表示了这个人在酒店的房间号。

4.TCP和UDP

1、TCP是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。它能够提供两台计算机之间的可靠的数据流,HTTP、FTP、Telnet等应 用都需要这种可靠的通信通道。

2、UDP是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传送目的地,至于能够达到目的地,达到目的地的时间以及内容的正确性都是不能保证的。

既然有了保证可靠传输的TCP协议,为什么还要非可靠传输的UDP协议呢?原因有两个:

  • 1、可靠的传输是要付出代价的,对数据内容的正确性的检验必然会占用计算机处理时间和网络带宽。因此TCP的传输效率不如UDP高。
  • 2、许多应用中并不需要保证严格的传输可靠性,比如视频会议系统,并不要求视频音频数据绝对正确,只要能够连贯就可以了。所以在这些场景下,使用UDP更合适些。

5.Socket

Socket定义

套接字(通讯双方C/S协商好的约定),网络上两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket。应用程序通过套接字向网络发出请求或者应答网络请求。

image.png

网络通信的要素
  • 网络请求就是通过Socket建立连接然后互相通信

①IP地址(主机的唯一标识)
②端口号(定位程序,标示不同的进程)
③传输协议(通讯的规则)[常见的协议:TCP、UDP]


2.服务器端和客户端

服务器端和客户端的定义与联系
  • 服务器端:

服务端是为客户端服务的,服务的内容诸如向客户端提供资源,保存客户端数据。例如:手机的存储、数据处理

  • 客户端:

客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务器端互相配合运行 例如:手机app 浏览器 桌面QQ

客户端、服务器端模拟
demo1—实现客户端和服务器端传递数据:( 注意端⼝号必须相同 先运⾏Server 再运⾏Client)
  • 服务器端
  • 1.新建一个Server类,并在类中写一个main方法
  • 2.创建服务器端的ServerSocket(直接创建一个ServerSocket对象,并写一个端口 ) (注意:端口的值不能太大,否则会出现异常!!!)
  • 3.获取连接的客户端的socket
  • 4.向客户端发送数据
  • 5.接收客户端发来的数据
//模拟服务器端
class Server{
    public static void main(String[] args)throws IOException{
        //1.创建服务器端的ServerSocket
        ServerSocket ss=new ServerSocket(8989);

        //2.获取连接的客户端的socket
        Socket clientSocket=ss.accept();

        //3.向客户端发送数据
        //BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(cilentSocket.getOutputStream()));
        PrintStream ps=new PrintStream(clientSocket.getOutputStream());
        ps.println("登录成功");
        clientSocket.shutdownOutput();
        //4.接收客户端发来的数据
        BufferedReader br=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String line=null;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }
    }
}

ps:

  • 1.在创建ServerSocket对象时会出现 异常,这时需要抛出异常或自己处理异常,上图代码采取的是系统自动抛出异常
  • 2.向客户端发送数据有两种方式,一种用BufferedWriter,一种用 **PrintStream**
  • 3.向客户端发送数据后需要关闭数据

  • 客户端:
  • 1.新建一个Client类
  • 2.创建用于通信的socket (指明和谁通信:ip地址 端口号)
  • 3.接收服务器端的数据
  • 4.读取服务器端发来的数据
  • 5.客户端向服务器端发送数据
class Client{
    public static void main(String[] args) throws IOException {
        //1.创建用于通信的socket
        //指明和谁通信:ip地址 端口号
        Socket socket=new Socket("192.168.43.121",8989);
        //接收服务器端的数据
       BufferedReader br=new BufferedReader( new InputStreamReader(socket.getInputStream()));
        //读取服务器端发来的数据
       // socket.getOutputStream();
        String line =null;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }
        //客户端向服务器端发送数据
        PrintStream ps=new PrintStream(socket.getOutputStream());
        ps.println("你好啊!");
        socket.shutdownOutput();
    }
}

ps:

  • 1.在创建Socket对象时会出现 异常,这时需要抛出异常或自己处理异常,上图代码采取的是系统自动抛出异常
  • 2.向服务器端发送数据后需要关闭数据

运行结果:


13X5Q9@V9${O__R@$NZPKA5.png

image.png

demo2—实现服务器端⼿动输⼊,将输⼊的内容发送给客户端 ,可以⼀直发( 注意端⼝号必须相同 先运⾏Server 再运⾏Client)
  • 服务器端
class MyServer{
    public static void main(String[] args){
        //创建ServerSocket
        try (ServerSocket ss = new ServerSocket(8888)){
            //监听客户端的连接
            Socket socket = ss.accept();

            //从终端接收数据
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            //获取向客户端输出数据的输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;

            while ((line = keyin.readLine()) != null){
                //发送给客户端
                ps.println(line);
            }

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

}
  • 客户端:
class Myclient{
    public static void main(String[] args){
        //连接服务器端的socket
        Socket socket = null;
        try{
            socket = new Socket("192.168.43.121",8888);

            //接收服务器端信息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }

            //从键盘输入数据 发送给服务器端
        } catch (IOException e) {
            System.out.println("网络出错 请重新登录");
        } finally {
            //关闭连接
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

PS:

  • 1.创建的对象的时候有异常,此时应该捕获异常,并且最后还要用finally来关闭(finally是必须执行的,有清理资源等作用),finally有异常进行捕获
  • 2.**demo1与demo2最大的区别是demo2实现了从终端输入
    BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
    运行结果
    20190821_221949.gif
demo3—实现客户端向服务器端上传图⽚
  • 服务器端
class Server{
    public static void main(String[] args) throws IOException {
        //创建服务器端的ServerSoket
        ServerSocket ss = new ServerSocket(8080);

        //监听客户端连接
        //当有客户端来连接这个服务器 就可以得到对应的socket
        //当没有客户端来连接 服务器一直在这里等待
        Socket socket = ss.accept();

        //创建客户端对应的输出流 用于向这个客户端发送数据
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("连接成功 可以发数据了!");

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        String path = "F:/JAVA/DAY12/Day1/src/main/java/Day12/java/media/1.jpg";
        FileOutputStream fos = new FileOutputStream(path);

        byte[] buf = new byte[1024];
        int len = -1;
        while((len = bis.read(buf)) != -1){
            fos.write(buf,0,len);
        }
    }
}
  • 客户端:
class Client{
    public static void main(String[] args) throws IOException {
        //连接服务器 获取socket
        Socket socket = new Socket("192.168.43.121",8080);

        //创建服务器端对应的输入流 用于接收服务器端发来的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        System.out.println(br.readLine());

        //向服务器端发送文件(图片)
        //1.将文件写入到内存里
        String path = "C:/Users/Administrator.000/Desktop/psd/4456d40b75f2f8b4";
        FileInputStream fis = new FileInputStream(path);

        //2.创建字节流 outputStream
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] buf = new byte[1024];
        int len = -1;
        while ((len = fis.read(buf)) != -1){
            bos.write(buf,0,len);
        }
        socket.shutdownOutput();
    }
}
7$Q(QXO8O`DV1A284FI5`Y4.png

U5BV(){G)`CG_I4KV{_85MV.png

PS:

  • 我选择图片时用png格式不能成功,如果用png格式不行,可以换一个格式看看

demo4—使⽤多线程实现对聊

为什么要用多线程实现?

  • 聊天的过程是双向,同时进行的
class Client{
    public static void main(String[] args)throws IOException {
        Socket socket=new Socket("192.168.43.121",8888);
        //用一个子线程处理服务器端数据
        new Thread(new ClientThread(socket)).start();

        //主线程处理终端输入发送给服务器端
        BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps=new PrintStream(socket.getOutputStream());
        String line=null;
        while((line=keyin.readLine())!=null){
            ps.println(line);
        }
    }
}

/**
 * 创建一个子线程处理客户端接收服务器端数据
 */
class ClientThread implements Runnable{
    private Socket socket;
    //保存操作socket
    public ClientThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        BufferedReader br=null;
        try {
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //读取数据
            String line=null;
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
        }catch(IOException e){
            System.out.println("网络出错 请重新登录");
            System.exit(-1);
        }finally{
            try {
                if (br != null) {
                    br.close();
                }
                if(socket!=null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
                }
         }
    }
}
class Server{
    public static void main(String[] args)throws IOException{
        ServerSocket ss=new ServerSocket(8888);
        //获取客户端的socket
        Socket socket= ss.accept();

        new ServerThread(socket).start();

        //从终端输入流对象
        BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
        //客户端的输出流对象
        PrintStream ps=new PrintStream(socket.getOutputStream());

        //读取终端的输入 将输入输出给客户端
        String line=null;
        while((line=keyin.readLine())!=null){
            ps.println(line);
        }
    }
}
/**
 * 服务器端创建一个子线程处理服务器端接受客户端的数据
 */
class ServerThread extends Thread{
    private Socket socket;
    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br =null;
        try {
             br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line=null;
                while((line=br.readLine())!=null){
                    System.out.println(line);
            }
        }catch(IOException e){
            System.out.println("网络出错 请重新登录");
            System.exit(-1);
        }finally{
            try {
                if (br != null) {
                    br.close();
                }
                if(socket!=null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

PS:

  • 1.上图的demo中创建子线程用了继承Thread的方法
    运行结果:


    ![`]E13M5$OXFI)N2MF2N368E.png
image.png
demo4—实现群聊
  • Client和ClientThread代码和对聊不变,主要在Server⾥添加数组和监听客户端连接


    2ZPYR{~)(5IS2J_AEAVR_QG.jpg
class server{
    public static ArrayList<Socket> sockets=new ArrayList<>();
    public static void main(String[] args)throws IOException {
        ServerSocket ss=new ServerSocket(6666);

        //不停的等待用户端连接
        while(true) {
            Socket socket = ss.accept();
            //当有客户端连接过来了 就保存
            sockets.add(socket);

            //开启一个线程处理每个客户端的输入
            new ServerThread(socket).start();
        }
    }
}
/**
 * 服务器端创建一个子线程处理服务器端接受客户端的数据
 */
class ServerThread extends Thread{
    private Socket socket;
    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br =null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line=null;
            while((line=br.readLine())!=null){
                //群发消息
                //遍历数组
                for(Socket s:server.sockets){
                    PrintStream ps=new PrintStream(s.getOutputStream());
                    ps.println(line);
                }
            }
        }catch(IOException e){
            System.out.println("网络出错 请重新登录");
            System.exit(-1);
        }finally{
            try {
                if (br != null) {
                    br.close();
                }
                if(socket!=null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}
class Client{
    public static void main(String[] args)throws IOException {
        Socket socket=new Socket("192.168.43.121",6666);
        //用一个子线程处理服务器端数据
        new Thread(new ClientThread(socket)).start();

        //主线程处理终端输入发送给服务器端
        BufferedReader keyin=new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps=new PrintStream(socket.getOutputStream());
        String line=null;
        while((line=keyin.readLine())!=null){
            ps.println(line);
        }


    }

}

/**
 * 创建一个子线程处理客户端接收服务器端数据
 */
class ClientThread implements Runnable{
    private Socket socket;
    //保存操作socket
    public ClientThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        BufferedReader br=null;
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //读取数据
            String line=null;
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
        }catch(IOException e){
            System.out.println("网络出错 请重新登录");
            System.exit(-1);
        }finally{
            try {
                if (br != null) {
                    br.close();
                }
                if(socket!=null) {
                    socket.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

20190821_231418.gif

PS:

  • 所连接的所有客户端,端口号必须一致!!!
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容