Java网络编程入门

网络编程是对信息的发送和接收处理。



一、基础点


*
* 网络编程概述
*   Java中提供网络类库,可以实现网络连接,底层由JVM控制,且Java实现跨平台的网络库
*   程序员所面对的是一个统一的网络编程环境
* 计算机网络:把分布在不同地理区域的计算机和专门的外部设备用通信线路互连成一个规模大、
*   功能强的网络系统,从而使得众多的计算机和外部设备能互相传递信息、共享硬件、软件和数据资源等
* 网络编程目的:直接或间接的通过网络协议与其他计算机实现数据交换,进行通信
*   主要两个问题:1 如何准确的定位网络的一台和多台主机,且定位主机上特定的应用
*              2 找到主机后如何可靠高效的进行数据传输
* 网络通信
*   通信双方地址:1 IP 2 端口号
*   一定的规则(网络通信协议)
*       3 OSI参考模型
*       4 TCP/IP参考模型(TCP/IP协议):国际标准
*   通信要素1 :IP地址
*       -- 唯一的标识Internet上的计算机(通信实体)
*       -- 本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
*       -- 分类方式1:IPV4和IPV6
*           IPV4:4个字节组成,40-255.大概42亿个地址,30亿都在北美?亚洲4亿。2011年初已经用完。
*               以点分十进制表示,如192.168.0.1
*           IPV6: 128位(16个字节)。写成8个无符号整数,每个整数用四个十六进制表示,数之间用 :隔开
*3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
*       -- 分类方式2: 公网地址(万维网使用)和私有地址(局域网)
*           192.168.开头的是私有地址,范围192.168.0.0 - 192.168.255.255,为组织机构内部使用
*   通信要素2 :端口号
*     端口号标识正在计算机上运行的进程(程序)
*       -- 不同的进程有不同的端口号
*       -- 规定为16位的整数 0~65535
*       -- 端口分类
*           公认端口:0~1023。被预先定义的服务通信占用(如HTTP占用端口80,FTP占用21Telnet占用23*           注册端口:1024~49151。分配给用户进程或应用进程
*               如(Tomcat占用端口8080MySQL占用3306Oracle占用1521等)
*           动态/私有端口:49152~65535
*     端口号和IP地址组合得出一个网络接口:Socket
*
* 网络协议
*   TCP/IP协议 传输控制协议TCP、网络互联协议IP,是一组协议包括多个具有不同功能且互关联的协议
*       IP协议是网络层的主要协议,支持网络件互连的数据通信
*       TCP/IP协议模型从实用角度出发,形成高效的四层体系结构,即数据链路层、IP层、传输层和应用层
*       TCP三次握手:为了对每次发送的数据进行跟踪和协商,确保数据段的发送和接收同步,根据
* 			所接收到的数据量确认数据发送、接收完毕后何时撤销联系,并建立虚连接,
*           防止历史连接初始化了连接。TCP建立连接是三次握手,连接终止是四次握手
*        第一次:建议连接时,客户端发送SYN包(seq=x)到服务器,并进入SYN_SENT状态,
* 				等待服务器确认。SYN(同步序列编号)
*        第二次:服务器收到SYN包,必须确认客户端的SYN(ACK=x+1),同时自己发送一个SYN包(seq=k)
*           即SYN+ACK包,此时服务器进入SYN_RECV状态
*        第三次:客户端收到服务器的SYN+ACK包,向服务器发送确认包(ACK=k+1),此包发送完毕,
* 				客户端和服务器进入ESTABLISHED
*           (TCP)连接成功,完成三次握手
*       TCP终止连接时四次挥手
*          1 客户端在发送最后一条数据时,给予数据标记FIN,告诉服务器,我将要断开连接了
*          2 服务器收到FIN请求后,并不立即用FIN报文段回复客户端,而是先向客户端发送确
* 				认序号ACK,同时通知自己相应的应用程序
*            :对方请求关闭连接(先发生ACK是为了防止这段时间客服端重传FIN报文段)。相当于
* 				回复客服端:请暂时别断开连接,待我告知服务器端应用程序,并处理
*          3 服务器的应用程序接收到消息,进行相应的处理,回复可以关闭。此时服务器向客户端
* 				发送FIN报文段
*          4 客户端收到FIN报文段,向服务器发送ACK表示彻底断开连接
*   Socket
*       网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的 标识符 套接字(Socket*       通信两端都需要有Socket,是两台机器通信的端点
*       网络通信其实就是Socket之间的通信
*       Socket允许程序把网络当成一个流,数据在两个Socket之间通过IO传输
*       一般主动发起通信的应用程序属于客户端,等待通信请求的位服务端
*       分类:stream socket:使用TCP提供可依赖的字节流服务数据报套接字
*           datagram socket:使用UDP提供“尽力而为”的数据报服务
*   常用方法:
*       Socket类的常用构造器
*           public Socket(InetAddress address, int port),创建一个流套接字将其连接到指定
* 				IP地址的端口号
*           public Socket(String host, int port),创建一个流套接字将其连接到指定主机上的端口号
*       Socket类的常用方法
*           public InputStream getInputStream(): 返回套接字的输入流,用于接收网络消息
*           public OutputStream getOutputStream(): 返回套接字的输出流,用于发送网络消息
*           public InetAddress getInetAddress(): 套接字连接的远程IP地址。如果未连接,返回null
*           public InetAddress getLocalAddress(): 获取套接字绑定的本地地址。即本地IP地址
*           public int getPort(): 获取此套接字连接到的远程端口号,如果尚未连接,返回0
*           public int getLocalPort(): 获取此套接字连接到的本地端口号,如果尚未绑定,返回-1
*           public void close(): 关闭套接字。关闭后,需要重新绑定才能使用。关闭套接字也会
* 				关闭该套接字的InputStreamOutputStream
*           public void shutdownInput(): 关闭该套接字的输入流。即不能在从该套接字的输入流
* 				中接受任何数据
*           public void shutdownOutput(): 禁止关闭套接字的输出流。对于TCP套接字,任何以
* 				前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。如果关闭输出流后写
* 				入数据,则该流将抛出IOException。既不能通过此套接字的输出流发送数据
*   客户端
*       客户端Socket的工作过程包括以下四个步骤
*       1 创建Socket:根据指定服务端的IP地址或端口号构造Socket类对象。若服务端响应,则建立
* 			客户端到服务端的通信线路若连接失败,会出现异常
*       2 打开连接到Socket的输入/输出流进行数据传输:getInputStream()/getOutputStream()
*       3 按照一定的协议对Socket进行读写操作:通过输入流度服务器放入线路的信息(但不能读自
* 			己放入线路的信息)通过输出流将信息写入线程
*       4 关闭Socket:断开客户端到服务器的连接,释放线路
*       客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接
*       Socket(String host, int port) throws UnknownHostException, IOException*           向服务器(域名是host,端口是port)发起TCP连接,连接成功则创建对象
*       Socket(InetAddress address, int port) throws IOException*           根据InetAddress对象所表示的IP地址以及端口号port发起连接
*       	客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请求
*   服务端
*       服务端程序Socket的工作过程包括以下四个步骤
*       1 调用ServerSocket(int port): 创建一个服务端套接字,并绑定到指定端口上,用于监听
* 			客户端请求
*       2 调用accept(): 监听连接请求,如果客户端请求连接,则接收此连接,返回通信套接字对象
*       3 调用 该Socket类对象的 getInputStream()/getOutputStream(),开始网络数据的发送和接收
*       4 关闭ServerSocket,客户端访问结束,关闭通信套接字
*       ServerSocket对象负责等待客户端请求建立套接字连接
*
*   UDP:称为用户数据报协议(UDP,User Datagram Protocol*       UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法
*       UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输
* 			的可靠性由应用层负责
*       Java中类DatagramSocketDatagramPacket实现了基于UDP协议网络程序
*       UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能安全送
* 			到目的地,也不确定何时送达
*       DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收
* 			端的IP地址和端口号
*       UDP协议中每个数据报都给出了完整的地址信息,无需建立发送方和接收方的连接。如同发快递包裹
*       DatagramSocket 类中常用方法
*           public DatagramSocket(int port): 创建数据报套接字,并绑定本地主机上的指定端口
*               套接字被绑定到通配符地址,IP地址由内核决定
*           public DatagramSocket(int port,InetAddress addre): 创建数据报套接字,并绑定
* 				本地地址。本地端口必须在0~65535之间(包括关系)。如果IP地址为0.0.0.0,套接
* 				字将被绑定到。通配符地址,IP地址由内核决定
*           public void close(): 关闭此数据报套接字
*           public void send(DatagramPacket p): 从此套接字发送数据包。DatagramPacket* 				含的信息指示:将要发送的数据、其长度、远程主机的IP地址和端口号
*           public void receive(DatagramPacket p): 从此套接字接收数据包。
*           public InetAddress getLocalAddress(): 获取套接字绑定的本地主机地址。
*           public int getLocalPort(): 获取此套接字绑定的本地主机端口号
*           public InetAddress getInetAddress(): 套接字连接的地址。如果未连接,返回null
*           public int getPort(): 获取此套接字连接到的远程端口号,如果尚未连接,返回-1
*      DatagramPacket 类中常用方法
*           public DatagramPacket(Byte[] buf, int length): 构造DatagramPacket,用来接
*               收长度为length的数据包,length参数必须小于等于buf.length
*           public DatagramPacket(Byte[] buf, int length, InetAddress address, int port):
 *              构造数据包,将长度为length的包发送到指定主机上的指定端口号。
*           public InetAddress getInetAddress(): 返回某台远程主机的IP地址
*           public int getPort(): 返回某台远程主机的端口号,此数据报是将要发往该主机的或
* 				从该主机接接收的
 *          public byte[] getData(): 返回数据缓冲区
*           public getLength(): 返回将要发送或接收到的数据的长度
*
* OSI七层
*     应用层:是网络向用户提供服务的窗口,主要用来支持用户的需求,人的需求 不同,应用层奇数也就不同
*         提供了多种应用服务:电子邮件(MHS)、文件传输(FTAM)、虚拟终端(VT)、电子数据交换(EDI)*         主要协议:FTP(21) SMTP(25) DNS.HTTP(80)
*     表示层:为通信提供一种公共的语言,方便交互,不同计算机系统结构使用的数据表示不同
*         如:IBM主机使用的是EBCDIC编码,而大部分PC使用ASCII编码
*         其他功能如:数据加密、数据压缩等
*     会话层:提供的服务可以使应用建立和维持会话,且能使会话同步
*     传输层:两个计算机通过网络进行数据传输时,是端到端的,具有缓冲作用
*         协议:TCP/UDP
*     数据链路层:可以理解为数据通道
*         MAC地址表示唯一性
*     物理层:为数据端设备提供传输数据的通路, 数据通路可以是一个物理媒体,可以是多个物理媒
* 			体链接而成。(比特流传输)
*     网络层:IP,以IP报文形式进行数据传入
* */

二、TCP


*
* rt.jar 下的java/net下 的类,是网络编程
* 网络架构:B/SC/S
*   B/SBrowser/Server,基于浏览器的,比如网页版淘宝
*   C/SClient/Server,基于客户端,如果手机APP或者PC端应用程序淘宝
* TCP:
*   能重传,不丢包,如果丢失会记录,重新发送
*   可靠
*   有序,顺序不会错,不如向服务端发送123,2丢失了,那你接受的可能是132。但收到的一定是123
*   面向连接,如果无连接,数据不会发送
*   三次握手,可保证数据安全性,能够保证数据交互
*   相当于打电话,只有电话接通了才能传输信息
* UDP:
*   速度快
*   不保证可靠
*   可能丢包
*   无连接
*   相当于发短信,不管是否收到,发过去就行
* */

public class _02_TcpClient {

    public static void main(String[] args) throws IOException {
        test2();
    }

    /**
     * 单次连接
     * @throws IOException
     */
    public static void test1() throws IOException {
        // 创建对象,指定IP和端口
        Socket socket = new Socket("127.0.0.1",1000);
        // 获取输入流,用于获取服务端传递的数据
        InputStream is = socket.getInputStream();
        // 转换为字符流,并指定编码
        InputStreamReader isr = new InputStreamReader(is,"utf-8");
        // 字符缓冲流
        BufferedReader br = new BufferedReader(isr);
        String tmp;
        while ((tmp= br.readLine())!=null){
            System.out.println(tmp);
        }
        br.close();
        socket.close();
    }

    /**
     * 阻塞式接收和发送
     * @throws IOException
     */
    public static void test2() throws IOException {
        // 创建对象,指定IP和端口
        Socket socket = new Socket("127.0.0.1",1000);

        // 通过输出流向客户端返回数据
        OutputStream os = socket.getOutputStream();
        // 转换为字符输出,指定编码utf-8
        OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
        // 封装打印流(写出用打印流)
        PrintWriter bw = new PrintWriter(osw);

        // 获取输入流,用于获取服务端传递的数据
        InputStream is = socket.getInputStream();
        // 转换为字符流,并指定编码
        InputStreamReader isr = new InputStreamReader(is,"utf-8");
        // 字符缓冲流
        BufferedReader br = new BufferedReader(isr);

        // 控制台输入
        Scanner scanner = new Scanner(System.in);
        String msg = scanner.nextLine();

        while (true){
            // 发送服务端
            bw.println(msg);
            bw.flush();
            // 接收服务端数据
            System.out.println(br.readLine());
            // 控制台输入
            msg = scanner.nextLine();
        }

    }
}

public class _01_TcpServer {

    public static void main(String[] args) throws IOException {
        test2();
    }

    /**
     * 单次连接
     * @throws IOException
     */
    public static void test1() throws IOException {
        // 创建对象并开启端口
        ServerSocket serverSocket = new ServerSocket(1000);
        System.out.println("服务器启动,等待客户端连接");
        // 等待客户端连接执行到这里线程会停下来,直到客户端连接成功
        // 客户端连接之后,会得到该Socket对象
        // 这个Socket可理解为 客户端,包含客户端锁传递的信息
        Socket socket = serverSocket.accept();
        System.out.println("客户端已连接");

        // 通过输出流向客户端返回数据
        OutputStream os = socket.getOutputStream();
        os.write("你好吗?最近咋样!".getBytes(StandardCharsets.UTF_8));
        os.flush();
        // 先开启的后关闭
        os.close();
        socket.close();
        serverSocket.close();
        System.out.println("连接已关闭");
    }

    /**
     * 阻塞式接收和发送
     * @throws IOException
     */
    public static void test2() throws IOException {
        // 创建对象并开启端口
        ServerSocket serverSocket = new ServerSocket(1000);
        System.out.println("服务器启动,等待客户端连接");
        // 等待客户端连接执行到这里线程会停下来,直到客户端连接成功
        // 客户端连接之后,会得到该Socket对象
        // 这个Socket可理解为 客户端,包含客户端锁传递的信息
        Socket socket = serverSocket.accept();
        System.out.println("客户端已连接");

        // 通过输出流向客户端返回数据
        OutputStream os = socket.getOutputStream();
        // 转换为字符输出,指定编码utf-8
        OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
        // 封装缓冲流
        PrintWriter bw = new PrintWriter(osw);

        // 接收数据,用输入流
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is,"utf-8");
        BufferedReader br = new BufferedReader(isr);

        // 读数据
        String tmp;
        // 阻塞式接收和发送
        while ((tmp= br.readLine())!=null){
            System.out.println("客户端发来信息:"+tmp);
            bw.println("您给服务端发送的数据为:"+tmp+"。服务端以收到");
            bw.flush();
        }

        // 先开启的后关闭
        bw.flush();
        socket.close();
        serverSocket.close();
        System.out.println("连接已关闭");
    }
}

三、UDP


public class _02_UdpClient {

    public static void main(String[] args) throws IOException {
        test1();
    }

    /**
     * 一次发送
     */
    public static void test1() throws IOException {
        // 发送数据
        String str = "你好!";
        // 字节数字输出流, 这一块相当于数据包装
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        // 写数据到baos
        dos.writeUTF(str);
        // 把baos转换为字节数组
        byte[] buf = baos.toByteArray();
        // System.out.println(new String(buf));

        // 发送的数据包,大小限制为64k,绑定地址
        DatagramPacket dp = new DatagramPacket(
                buf, buf.length,new InetSocketAddress("127.0.0.1",1000));
        // 发送,需要通过电脑中一个端口发出去
        DatagramSocket ds = new DatagramSocket(9999); // 通信
        // 发送dp数据包
        ds.send(dp);
        ds.close();
    }

    /**
     * 持续发送
     */
    public static void test2() throws IOException {
        // 发送数据
        String str = null;
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入需要传递的信息:");
        str = scanner.nextLine();

        while (str!=null){
            // 字节数字输出流, 这一块相当于数据包装
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            // 写数据到baos
            dos.writeUTF(str);
            // 把baos转换为字节数组
            byte[] buf = baos.toByteArray();
            // System.out.println(new String(buf));

            // 发送的数据包,大小限制为64k,绑定地址
            DatagramPacket dp = new DatagramPacket(
                    buf, buf.length,new InetSocketAddress("127.0.0.1",1000));
            // 发送,需要通过电脑中一个端口发出去
            DatagramSocket ds = new DatagramSocket(9999); // 通信

            // 发送dp数据包
            ds.send(dp);
            ds.close();

            // 如果输入exit,退出客户端
            if (str.equalsIgnoreCase("exit")){
                break;
            }

            // 循环输入
            System.out.println("请输入需要传递的信息:");
            str = scanner.nextLine();
        }
    }
}

public class _01_UdpServer {

    public static void main(String[] args) throws IOException {
        // 打开UDP对象
        DatagramSocket ds = new DatagramSocket(1000);
        // 声明一个字节数字,用来存放收到的数据
        byte[] buf = new byte[1024];
        // 包接收器,把接收到的数据存放在byte数组中
        DatagramPacket dp = new DatagramPacket(buf,buf.length);

        // 阻塞式接收
        while (true){
            // 监听接收
            ds.receive(dp);

            // 字节数组输入流
            ByteArrayInputStream bais = new ByteArrayInputStream(buf);
            // 转换为数据流
            DataInputStream dis = new DataInputStream(bais);
            // 数据读取
            String msg = null;
            msg = dis.readUTF();
            // 如果收到exit 则退出服务端
            if (msg.equalsIgnoreCase("exit")){
                break;
            }
            System.out.println(msg);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值