网络编程

网络编程

1、网络编程基本概念

  • 1、什么是计算机网络
    • 把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大、功能强的网络系统,从而使众多的计算机可以方便的互相传递信息,共享硬件、软件、数据信息等资源、
  • 2、计算机网络的主要功能
    • 资源共享
    • 信息传输与集中处理
    • 均衡负荷与分布处理
    • 综合信息服务(www/综合业务数字网络ISDN)等
  • 3、网络通信协议
    • 要使计算机连成的网络互相通信,需要对数据传输速率、传输代码、代码结构、传输控制步奏、出错控制等制定一组标准,这一组共同遵守的通信标准就是网络通信协议,不同的计算机之间必须使用相同的通讯协议才能进行通信
  • 4、网络通信接口
    • 为了使两个节点之间进行对话,必须在他们之间建立通信工具(接口),使彼此之间能够进行信息交换,接口包括两部分
      • 1、硬件装置:实现节点之间的信息传递
      • 2、软件装置:规定双方进行通信的约定协议
  • 5、程序开发结构
    • 网络编程主要是指完成C/S程序的开发,程序的开发结构有以下两种
    • C/S(客户端/服务器端)
      • 开发两套程序,两套程序都需要维护,例如 QQ,CS程序一般比较稳定
  • B/S(游览器端/服务端)
    • 开发一套程序,客户端使用游览器进行访问,例如:各个论坛,BS程序一般稳定性差,而且安全性较差,但是C/S的程序开发在实际的java应用中毕竟很少了,而且整个java基本上都是B/S为主
  • C/S程序主要可以完成以下两种程序的开发:
    • TCP:传输控制协议,采用三方握手的方式,确保准确的连接操作
    • UDP:数据报协议,发送数据报,例如:手机短信或者QQ消息
    • TCP/UDP的数据帧格式简答图例:
      • 协议类型 | 源IP | 目标IP | 源端口 | 目标端口 | 帧序号 | 帧数据
      • 其中协议类型用于区分TCP/UDP

2、网络编程TCP协议

  • 传输控制协议/因特网互联协议,又称为网络通讯协议,这个协议是Internet最基本的协议,Internet国际互联网络的基础,简单的说就是由网络层的IP协议和传输层TCP协议组成的
    • IP地址:网络中每台计算机的一个标识号码
    • 本机IP:127.0.0.1 localhost
    • 端口号(PORT):端口号的范围065535之间,01023之前的端口数是用于一些知名的网络服务和应用
    • 应用层-->表示层-->会话层-->传输层-->网络层-->数据链路层--->物理层
  • 1、TCP程序概述
    • TCP是一个可靠的协议,面向连接的协议
      • 实现TCP程序,需要编写服务器端和客户端,Java API为我们提供了java.net包,为实现网络应用程序提供类
      • ServerSocket:此类实现服务器套接字
      • Socket:此类实现客户端套接字(也可以叫“套接字”)
      • Socket是网络驱动层提供给应用程序编程的接口和一种机制
  • 2、实现服务器端和客户端程序
    • 服务器端

              public class ServerSocket extends Object 
      
    • 此类实现服务器套接字,服务器套接字等待请求通过网络传入,它基于该请求执行某些操作,然后可能向请求者返回结果。

                ServerSocket(int port)
                创建绑定到特定端口的服务器套接字
    
                void setSoTimeout(int timeout)
                通过制定超市值启用/禁用SO_TIMEIOUT  以毫秒为单位
                
                InetAddress getInetAddress()
                返回此服务器套接字的本地地址
                
                Socket accept()
                帧听并接受此套接字的连接

* 实现服务器端与客户端程序
       * 客户端
       
                 public class Socket extends Object
                此类实现客户端套接字(也可以就“套接字”),套接字是两台机器间通信的端点
                  Socket(String host,int port)
                 创建一个流套接字并将其连接到指定主机上的指定端口号
            
                InputStream getInputStream()
                返回次套接字的输入流
            
                OutputStream getOutputStream()
                返回此套接字的输出流
                
                void setSoTimeout(int timeout)
                启用/禁用带有指定超时值得SO_TIMEOUT,以毫秒为单位
                

3、TCP实现ECHO程序

服务端步奏:

      //服务器端
                    public static void main(String[] args) {
                    // 1024--65535
                    try {
                        //1、创建ServerSocket对象,绑定监听端口
                        ServerSocket ss = new ServerSocket(8888);
                        System.out.println("服务器已经启动,正在等待连接。。。");
                        //2、通过accept()方法监听客户端的请求
                        Socket socket = ss.accept(); // 表示客户端等待连接 会阻塞
                        //3、连接建立后,通过输入流读取客户端发送的请求信息
                        InputStream in = socket.getInputStream();
                        BufferedReader br = new BufferedReader(new InputStreamReader(in));
                        String info = br.readLine();
                        System.out.println(info);
                        //4、通过输出流向客户端发送响应的信息
                        OutputStream out = socket.getOutputStream();
                        PrintStream ps = new PrintStream(out);
                        ps.println("demo" + info);
                        //5、关闭相应的资源
                        out.close();
                        in.close();
            
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    }
                    
                    //客户端程序
                            // 连接服务器
                    try {
                        //创建Socket对象,指明需要连接的服务器的地址和端口号
                        Socket socket = new Socket("localhost", 8888);
                        System.out.println("连接成功");
                        // 输出流   连接建立后,通过输出流向服务器发送请求信息
                        OutputStream out = socket.getOutputStream();
                        // 输入流   通过输入流获取服务器响应的信息
                        InputStream in = socket.getInputStream();
            
                        PrintStream ps = new PrintStream(out);
                        ps.println("hello");
                        BufferedReader br = new BufferedReader(new InputStreamReader(in));
                        System.out.println(br.readLine());
                        //关闭相应的资源
                        out.close();
                        in.close();
            
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    }

4、服务器与多客户端通信

  • 目前为止我们编写的程序中,服务器只能处理一个客户端连接,要想服务器同时支持多个客户端的连接,就必须加入多线程的处理机制,将每一个连接的客户端创建一个新的线程对象。

  • 应用多线程来实现服务器与多客户端之间的通信

    • 基本步奏
      • 1、服务器端创建ServerSocket,循环调用accept()等待客户端连接
      • 2、客户端创建一个socket并请求和服务器端连接
      • 3、服务器端接受客户端请求,创建socket与改客户端建立专线连接
      • 4、建立连接的两个socket在一个单独的线程中对话
      • 5、服务器端等待新的连接
              // 服务器端代码

                package com.yinlei.socket;
                
                import java.io.BufferedReader;
                import java.io.IOException;
                import java.io.InputStream;
                import java.io.InputStreamReader;
                import java.io.OutputStream;
                import java.io.PrintStream;
                import java.net.ServerSocket;
                import java.net.Socket;
                import java.util.concurrent.ExecutorService;
                import java.util.concurrent.Executors;
                
                import org.omg.CORBA.TRANSACTION_REQUIRED;
                
                public class MutilServer {
                
                    public static void main(String[] args) {
                
                        ExecutorService es = Executors.newCachedThreadPool();
                
                        try {
                            ServerSocket ss = new ServerSocket(8000);
                            System.out.println("服务器已经启动,正在等待连接。。。");
                
                            while (true) {
                                Socket socket = ss.accept(); // 等待客户端连接,阻塞
                                es.execute(new ClientThread(socket));
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                
                    static class ClientThread implements Runnable {
                
                        private Socket socket;
                    
                
                        public ClientThread(Socket socket) {
                            this.socket = socket;
                        }
                
                        @Override
                        public void run() {
                            try {
                                System.out.println("客户端的IP为:" + socket.getInetAddress().getHostName());
                                InputStream in = socket.getInputStream();
                                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                                
                                OutputStream out = socket.getOutputStream();
                                PrintStream ps = new PrintStream(out);
                                while (true) {
                                    String info = br.readLine();
                                    if (info==null || "bye".equals("bye")) {
                        break;
                    }
                                    System.out.println(info);
                                    ps.println("demo : " + info);
                                }
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                
                }

        //客户端代码
        package com.yinlei.socket;

                import java.io.BufferedReader;
                import java.io.InputStream;
                import java.io.InputStreamReader;
                import java.io.OutputStream;
                import java.io.PrintStream;
                import java.net.Socket;
                import java.util.Scanner;
                
                public class MutilSocket {
                
                    public static void main(String[] args) {
                        // 连接服务器
                        try {
                            Socket socket = new Socket("localhost", 8000);
                            System.out.println("连接成功");
                            boolean flag = true;
                            // 输出流
                            OutputStream out = socket.getOutputStream();
                            // 输入流
                            InputStream in = socket.getInputStream();
                
                            PrintStream ps = new PrintStream(out);
                            @SuppressWarnings("resource")
                            Scanner input = new Scanner(System.in);
                            System.out.println("请输入...");
                            while (flag) {
                                String info = input.next();
                                if ("bye".equals(info)) {
                                    flag = false;
                                    break;
                                }
                                ps.println(info);
                                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                                info = br.readLine();
                                System.out.println(info);
                            }
                
                        } catch (Exception e) {
                            e.printStackTrace();
                
                    }
                    }
                }

//服务器端接收数据



//客户端接收数据,有bye的时候退出


5、多客户端之间的通信

  • 客户端的数据包通过服务器中转,发送给另一个客户端

6、网络编程UDP协议

  • 1、UDP是User Datagram Protocol简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的原地址,或者目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的,每个被传输的数据报必须限定在64kb之内
  • 主要使用以下的两个类
    • DatagramPacket:此类表示数据报名字
    • DatagramSocket:此类表示用来发送和接收数据报的套接字
                //服务器端。。。

                    String info = "hello"; //将信息封装成数据报
                    byte[]bytes = info.getBytes();
                    try {
                        //客户端在5000端口监听
                        DatagramPacket dp = new DatagramPacket(bytes, 0,bytes.length,InetAddress.getByName("localhost"),5000);
                        DatagramSocket server = new DatagramSocket(3000);//服务器的端口
                        server.send(dp);
                        server.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } 
                    
                    //客户端代码。。。
                    
                byte[] bytes = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bytes, bytes.length);// 接受数据
                DatagramSocket client;
                try {
                    client = new DatagramSocket(5000);
                    client.receive(dp);
                    System.out.println(new String(dp.getData(), 0, dp.getLength()));
                    client.close();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }// 
                

7、URL

  • 1、URL概述
    • URL(uniform resource location)类URL代表一个统一资源定位符,它是值向互联网"资源"的指针,抽象类URLConnection是所有类的超类,它代表应用程序和URL之简单的通信链接
                        URL url = new URL("");
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
                        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:\\dasd.jpg"));
                        byte[]bs = new byte[1024];
                        int len = -1;
                        while((len = bis.read(bs)) != -1){
                            bos.write(bs,0,len);
                        }
                        bos.close();
                        bis.close();
                        System.out.println("success");

下载一个网络图片并且显示;

 new Thread() {
            //异步下载
            @Override
            public void run() {
                try {
                    URL url = new URL(image);
                    try {

                        InputStream is = url.openStream();
                        final Bitmap bitmap = BitmapFactory.decodeStream(is);

                        runOnUiThread(new Runnable() {
                            //主线程中更新UI
                            @Override
                            public void run() {
                                mImageView.setImageBitmap(bitmap);
                            }
                        });

                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

8、HttpURLConnection接口

Http通信中,的POST和GET请求方式不同,GET把参数放在URL字符串的后面,传递给服务器,而POST方法的参数是放在http请求中,因此,在编程之前,应当首先明确使用的请求方法,然后在依据使用的方法选择相应的编程方式
HttpURLConnection是继承于URLConnection类,二者都是抽象类,其对象主要通过URL的openConnection方法获得

try {
            HttpURLConnection conn = (HttpURLConnection) new URL(image).openConnection();
            conn.setDoOutput(true);  //post情况下需要设置为true,默认是false
            conn.setDoInput(true);  //设置是否从httpUrlConnection读入,默认是true
            conn.setRequestMethod("POST");
            conn.setUseCaches(true);  //设置是否用缓存,post请求不用缓存
            //设置content-type
            conn.setConnectTimeout(3000);  //设置连接超时
            conn.setReadTimeout(3000);  //设置读取超时
            
            
            //获取输出流,便于想服务器发送新消息
            DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
            //往流里面写请求参数
            dos.writeBytes("name=" + URLEncoder.encode("hello","gb2312"));
            dos.flush();
            dos.close();
            
            //获取输入流,取数据
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            br.readLine();  //用 !=null 来判断是否结束
            br.close();
            
            //关闭connection
            conn.disconnect();
            
            
        } catch (IOException e) {
            e.printStackTrace();
        }

9、UDP

  • UDP协议(用户数据报协议)是无连接、不可靠、无序的

  • UDP协议是以数据报作为数据传输的载体

  • 进行数据传输的时候,首先需要将要传输的数据定义成数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口号),然后在将数据报发送出去。

  • 相关操作类:

    • DatagramPacket:表示数据报包
    • DatagramSocket:进行端到端通信的类
  • 服务器端实现步奏:

    • 1、创建DatagragmSocket,指定端口号
    • 2、创建DatagramPacket
    • 3、接收客户端发送的数据信息
    • 4、读取数据
    // 1、创建DatagragmSocket,指定端口号
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(8888);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        // 创建字节数组,用于接收客户端发送的数据
        byte[] data = new byte[1024];
        // 2、创建DatagramPacket
        DatagramPacket packet = new DatagramPacket(data, data.length);
        // 3、接收客户端发送的数据信息
        try {
            socket.receive(packet);   //此方法在接收到数据报之前会一直阻塞
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 4、读取数据
        
        String info = new String(data, 0, packet.getLength());
        
        System.out.println("我是服务器---》"+ "客户端说:" +info);
        
        //-----------------------------------------------------------------------------
        /**
         * 向客户端响应数据
         */
        //定义客户端的地址、端口号、数据
        InetAddress address = null;
        address = packet.getAddress();
        int port = packet.getPort();
        byte[]data1= "欢迎您".getBytes();
        //创建数据报,包含响应的数据信息
        DatagramPacket packet2 = new DatagramPacket(data1, data1.length,address,port);
        
        DatagramSocket socket2 = null;
        try {
             socket2 = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        
        try {
            socket2.send(packet2);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //关闭资源
        socket.close();
        socket2.close();
    
  • 客户端实现步奏:
    • 1、 定义发送的信息
    • 2、创建DataframPacket,包含将要发送的信息
    • 3、创建DatagramSocket
    • 4、发送数据
    // 1、创建DatagragmSocket,指定端口号
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(8888);
        } catch (SocketException e) {
            e.printStackTrace();
        }
        // 创建字节数组,用于接收客户端发送的数据
        byte[] data = new byte[1024];
        // 2、创建DatagramPacket
        DatagramPacket packet = new DatagramPacket(data, data.length);
        // 3、接收客户端发送的数据信息
        try {
            socket.receive(packet);   //此方法在接收到数据报之前会一直阻塞
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 4、读取数据
        
        String info = new String(data, 0, packet.getLength());
        
        System.out.println("我是服务器---》"+ "客户端说:" +info);
        
        //-----------------------------------------------------------------------------
        /**
         * 向客户端响应数据
         */
        //定义客户端的地址、端口号、数据
        InetAddress address = null;
        address = packet.getAddress();
        int port = packet.getPort();
        byte[]data1= "欢迎您".getBytes();
        //创建数据报,包含响应的数据信息
        DatagramPacket packet2 = new DatagramPacket(data1, data1.length,address,port);
        
        DatagramSocket socket2 = null;
        try {
             socket2 = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        
        try {
            socket2.send(packet2);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //关闭资源
        socket.close();
        socket2.close();
    

总结:

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

推荐阅读更多精彩内容

  • iOS网络HTTP、TCP、UDP、Socket 知识总结OSI 七层模型我们一般使用的网络数据传输由下而上共有七...
    蜗牛也有梦想阅读 2,400评论 0 3
  • 1. 网络编程概述 1.1 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接...
    JackChen1024阅读 1,033评论 0 3
  • 引言 网络学习的核心内容就是网络协议的学习 网络协议:网络中进行数据交换而建立的规则、标准或者说是约定的集合因为不...
    _凉风_阅读 1,978评论 8 22
  • 商务聚餐,我浅笑着端起酒杯向着隔壁桌走去,“王总,你以后可得照顾我们生意啊。” “肖大美女都发话了,我岂敢不从啊,...
    605室草_暴雨阅读 326评论 0 0
  • 镜子里的人, 那么陌生 你是谁? 没有答案。 又一次面向镜子 正视自己, 你究竟是谁? 我就是我。
    心的光阅读 94评论 0 0