Java网络编程

一:计算机网络概述

计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。
按照地理位置覆盖可以分为局域网、城域网和广域网。
- 局域网:被用于连接公司办公室,实验室或者机房教室等。
- 城域网:覆盖城镇内的广大地理区域,是在一个城市范围内所建立的计算机通信网络,
- 广域网:覆盖广阔的地理位置,范围可以超越国界遍及全球。因而对通信要求以及复杂性较高。
网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。

二:网络分层模型

世界上第一个网络体系结构由IBM公司提出(1974年,SNA),以后其他公司也相继提出自己的网络体系结构如:Digital公司的DNA,美国国防部的TCP/IP等,多种网络体系结构并存,其结果是若采用IBM的结构,只能选用IBM的产品,只能与同种结构的网络互联。

OSI模型

为了促进计算机网络的发展,国际标准化组织ISO于1977年成立了一个委员会,在现有网络的基础上,提出了不基于具体机型、操作系统或公司的网络体系结构,称为开放系统互连参考模型,即OSI/RM (Open System Interconnection Reference Model)。

OSI模型把网络通信的工作分为7层,分别是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
这里写图片描述

  • 物理层

物理层处于OSI的最底层,是整个开放系统的基础。物理层涉及通信信道上传输的原始比特流(bits),它的功能主要是为数据端设备提供传送数据的通路以及传输数据。

  • 数据链路层

数据链路层的主要任务是实现计算机网络中相邻节点之间的可靠传输,把原始的、有差错的物理传输线路加上数据链路协议以后,构成逻辑上可靠的数据链路。需要完成的功能有链路管理、成帧、差错控制以及流量控制等。其中成帧是对物理层的原始比特流进行界定,数据链路层也能够对帧的丢失进行处理。

  • 网络层

网络层涉及源主机节点到目的主机节点之间可靠的网络传输,它需要完成的功能主要包括路由选择、网络寻址、流量控制、拥塞控制、网络互连等。

  • 传输层

传输层起着承上启下的作用,涉及源端节点到目的端节点之间可靠的信息传输。传输层需要解决跨越网络连接的建立和释放,对底层不可靠的网络,建立连接时需要三次握手,释放连接时需要四次挥手。

  • 会话层

会话层的主要功能是负责应用程序之间建立、维持和中断会话,同时也提供对设备和结点之间的会话控制,协调系统和服务之间的交流,并通过提供单工、半双工和全双工3种不同的通信方式,使系统和服务之间有序地进行通信。

  • 表示层

表示层关心所传输数据信息的格式定义,其主要功能是把应用层提供的信息变换为能够共同理解的形式,提供字符代码、数据格式、控制信息格式、加密等的统一表示。

  • 应用层。

应用层为OSI的最高层,是直接为应用进程提供服务的。其作用是在实现多个系统应用进程相互通信的同时,完成一系列业务处理所需的服务。

三:TCP/IP参考模型

OSI参考模型的初衷是提供全世界范围的计算机网络都要遵循的统一标准,但是由于存在模型和协议自身的缺陷,迟迟没有成熟的产品推出。TCP/IP协议在实践中不断完善和发展取得成功,作为网络的基础,Internet的语言,可以说没有TCP/IP协议就没有互联网的今天。

简介

TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础。

TCP/IP协议是一个开放的网络协议簇,它的名字主要取自最重要的网络层IP协议和传输层TCP协议。TCP/IP协议定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。TCP/IP参考模型采用4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求,这4个层次分别是:网络接口层、互联网层(IP层)、传输层(TCP层)、应用层。

这里写图片描述

  • 网络接口层

TCP/IP协议对网络接口层没有给出具体的描述,网络接口层对应着物理层和数据链路层。

  • 互联网层(IP层)

互联网层是整个TCP/IP协议栈的核心。它的功能是把分组发往目标网络或主机。同时,为了尽快地发送分组,可能需要沿不同的路径同时进行分组传递。因此,分组到达的顺序和发送的顺序可能不同,这就需要上层必须对分组进行排序。互联网层除了需要完成路由的功能外,也可以完成将不同类型的网络(异构网)互连的任务。除此之外,互联网层还需要完成拥塞控制的功能。

  • 传输层(TCP层)

TCP层负责在应用进程之间建立端到端的连接和可靠通信,它只存在与端节点中。TCP层涉及两个协议,TCP和UDP。其中,TCP协议提供面向连接的服务,提供按字节流的有序、可靠传输,可以实现连接管理、差错控制、流量控制、拥塞控制等。UDP协议提供无连接的服务,用于不需要或无法实现面向连接的网络应用中。

  • 应用层

应用层为Internet中的各种网络应用提供服务。

四:三次握手与四次挥手

TCP是面向连接的协议,因此每个TCP连接都有3个阶段:连接建立、数据传送和连接释放。连接建立经历三个步骤,通常称为“三次握手”。
这里写图片描述

第一次握手

  • 客户机发送连接请求报文段到服务器,并进入SYN_SENT状态,等待服务器确认。(SYN = 1,seq=x)

第二次握手

  • 服务器收到连接请求报文,如果同意建立连接,向客户机发回确认报文段,并为该TCP连接分配TCP缓存和变量。(SYN=1,ACK=1,seq=y,ack=x+1)。

第三次握手

  • 客户机收到服务器的确认报文段后,向服务器给出确认报文段,并且也要给该连接分配缓存和变量。此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。(ACK=1,seq=x+1,ack=y+1)。

四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
这里写图片描述

  • TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
  • 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
  • 服务器关闭客户端的连接,发送一个FIN给客户端。
  • 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

五:UDP协议:

UDP,用户数据报协议,英文全称是User Datagram Protocol,它是TCP/IP协议簇中无连接的运输层协议。

这里写图片描述

从图中可以看到,UDP协议十分简单,它由两部分组成:首部和数据。其中,首部仅有8个字节,包括源端口和目的端口,长度(UDP用于数据报的长度)、校验。

常见问题

OSI参考模型的分为哪几层,每层的功能?

OSI,开放系统互连参考模型,它的7个层次自顶到下依次为应用层,表示层,会话层,传输层,网络层,数据链路层和物理层。各层的功能见文章开始。

TCP协议和UDP协议的区别?

TCP协议是传输控制协议,UDP协议是用户数据报协议,两者都是传输层的协议,主要区别在于前者是可靠的,面向连接的协议,后者是不可靠的,无连接的协议。其它的区别还有,TCP协议传输速度慢,UDP常用于一次性传输比较少量数据的网络应用。

TCP三次握手为什么不能是两次?

主要是防止两次握手情况下已经失效的连接请求报文段突然又传送到服务端而产生错误。例如,客户机A向服务器B发送TCP连接请求,第一个连接请求报文在网络的某个节点长时间滞留,A超时后认为报文丢失,于是再重传一次连接请求,B收到后建立连接。数据传输完毕后双方断开连接,而这时之前滞留的连接请求到达了服务端B,而B认为A又发来连接请求。如果两次握手建立连接,A并无连接请求,造成B的资源浪费。

HTTP请求的GET方法和POST方法的区别?

GET和POST是HTTP请求的两种方法,主要区别在于GET方法是请求读取由URL所标志的信息,POST是给服务器添加信息。详解在这

在浏览器中输入网址到显示出页面的整个过程?

  1. 输出包含域名的网址
  2. 浏览器向DNS请求解析域名对应的IP地址
  3. 域名系统DNS解析出域名对应的IP地址
  4. 浏览器与该服务器建立TCP连接
  5. 浏览器发送HTTP请求
  6. 服务器通过HTTP响应把页面文件发送给浏览器
  7. TCP连接释放
  8. 浏览器解释文件,并显示

重点来了。JAVA网络编程

Java的网络编程主要涉及到的内容是Socket编程,那么什么是Socket呢?简单地说,Socket,套接字,就是两台主机之间逻辑连接的端点。TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket,本质上就是一组接口,是对TCP/IP协议的封装和应用(程序员层面上)。

Socket编程主要涉及到客户端和服务器端两个方面,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是0到65536,但是0到1024是为特权服务保留的端口号,我们可以选择任意一个当前没有被其他进程使用的端口。

客户端请求与服务器进行连接的时候,根据服务器的域名或者IP地址,加上端口号,打开一个套接字。当服务器接受连接后,服务器和客户端之间的通信就像输入输出流一样进行操作。
这里写图片描述
实例一:单线程客户端服务器

/*
 *客户端
 /
public class Client {
    public static void main(String[] args) {
        try {
            //建立客户端连接,设置IP地址和端口号
            Socket socket=new Socket("localhost", 5000);
            //打开输出流和输入流。向服务器传输数据和接收数据
            OutputStream out=socket.getOutputStream();
            InputStream in=socket.getInputStream();
            //向服务器写入数据
            String info="用户名:TOM;用户密码:1234";
            //向输入流中写入数据,传入String的byte数组
            out.write(info.getBytes());
            //及时关闭套接字的输出流
            socket.shutdownOutput();
            //接收服务器端的相应,即从输入流中读取数据
            String reply=null;
            //创建字符缓存流。用到字节字符转换流
            BufferedReader br=new BufferedReader(new InputStreamReader(in));
            while((reply=br.readLine())!=null){
                System.out.println("我是客户端,服务器的响应为:"+reply);
            }
            //关闭资源,后开先关
            br.close();
            in.close();
            out.close();
            socket.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
/*
 *服务端
 /

public class Server {
    public static void main(String[] args) {
        try {
            //创建ServerSocket指定端口名称
            ServerSocket serverSocket=new ServerSocket(5000);
            //accept()方法等待客户端触发信息
            Socket socket=serverSocket.accept();
            //打开输入输出流
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            //获取客户端信息,即从输入输出流中读取信息
            BufferedReader br=new BufferedReader(new InputStreamReader(in));
            String info=null;
            while((info=br.readLine())!=null){
                System.out.println("我是服务器,客户登陆的信息为:"+info);
            }
            //给客户端一个响应,向输出流中写入数据
            String reply="欢迎您,登陆成功";
            out.write(reply.getBytes());
            //关闭资源
            socket.shutdownOutput();
            br.close();
            out.close();
            in.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

实例二:单线程客户端服务器序列化操作

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket=new Socket("localhost", 5001);
            //打开输入输出流
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            //对象序列化输出流
            ObjectOutputStream oos=new ObjectOutputStream(out);
            User1 user=new User1("TOM","1234");
            oos.writeObject(user);
            //及时关闭socket的输出流
            socket.shutdownOutput();
            BufferedReader read=new BufferedReader(new InputStreamReader(in));
            String reply=null;
            while((reply=read.readLine())!=null){
                System.out.println("我是客户端,副武器的响应为:"+reply);
            }
            oos.close();
            out.close();
            in.close();

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

    }
}
public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket=new ServerSocket(5001);
            Socket socket=serverSocket.accept();
            //打开输入输出流
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            //对象反序列化
            ObjectInputStream ois=new ObjectInputStream(in);
            //获取客户端信息,即从输入流中读取信息
            User1 user=(User1) ois.readObject();
            if(user!=null){
                System.out.println("我是服务器,客户端的信息为:"+user.getName()+","+user.getPwd());
            }
            String info="您好,欢迎登录";
            out.write(info.getBytes());
            //关闭资源
            ois.close();
            out.close();
            in.close();

        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();    
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class User1 implements Serializable{
    private String name;
    private String pwd;
    public User1(String name,String pwd){
        this.name=name;
        this.pwd=pwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

}

实例三:多线程客户端服务器序列化操作

/*
 * 线程类
 */
public class LoginThread implements Runnable {
    //创建socket
    Socket socket=null;
    //构造传入一个socket
    public LoginThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            //打开输入输出流
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            //打开序列化输入流
            ObjectInputStream ois=new ObjectInputStream(in);
            User user=(User) ois.readObject();
            System.out.println("我是服务器,客户端的信息为:"+user.getName()+","+user.getPwd());
            socket.shutdownInput();
            String info="欢迎登录";
            out.write(info.getBytes());
            ois.close();
            out.close();
            in.close();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}
public class Server {
    public static void main(String[] args) {
        ServerSocket server;
        try {
            server = new ServerSocket(5003);
            //不断监听
            while(true){
                Socket socket=server.accept();
                Thread th=new Thread(new LoginThread(socket));
                th.start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
public class Client {
    public static void main(String[] args) {
        try {
            Socket socket=new Socket("localhost", 5003);
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(out);
            User user=new User("Lisa", "123456");
            oos.writeObject(user);
            socket.shutdownOutput();
            BufferedReader read=new BufferedReader(new InputStreamReader(in));
            String reply=null;
            while((reply=read.readLine())!=null){
                System.out.println("我是客户端,服务器的响应为:"+reply);
            }
            read.close();
            oos.close();
            out.close();
            in.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
public class Client2 {
    public static void main(String[] args) {
        try {
            Socket socket=new Socket("localhost", 5003);
            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(out);
            User user=new User("ToM", "123456789");
            oos.writeObject(user);
            socket.shutdownOutput();
            BufferedReader read=new BufferedReader(new InputStreamReader(in));
            String reply=null;
            while((reply=read.readLine())!=null){
                System.out.println("我是客户端,服务器的响应为:"+reply);
            }
            read.close();
            oos.close();
            out.close();
            in.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
public class User implements Serializable{
    private String name;
    private String pwd;
    public User(String name,String pwd){
        this.name=name;
        this.pwd=pwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

}

实例四:UDP编程实例(了解能看懂即可)

public class Client {
    public static void main(String[] args) {
        DatagramPacket dp=null;
        DatagramSocket ds=null;
        DatagramPacket dpto=null;
        //创建DatagramPacket对象,用来准备接收数据包
        byte[] buf=new byte[1024];
        dp=new DatagramPacket(buf, buf.length);
        try {
            //创建D阿塔gramSocket对象,接收数据
            ds=new DatagramSocket(8800);
            ds.receive(dp);
            //显示接收到的信息
            String mess=new String(dp.getData(), 0,dp.getLength());
            System.out.println(dp.getAddress().getHostAddress()+"说:"+mess);

            String reply="你好,我在,请咨询";
            //显示本地对话框
            System.out.println("我说:"+reply);
            //创建DatagramPacket对象,封装数据
            SocketAddress sa=dp.getSocketAddress();
            dpto=new DatagramPacket(reply.getBytes(), reply.getBytes().length,sa);
            ds.send(dpto);  
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            ds.close();
        }

    }
}
public class Server {
    public static void main(String[] args) {
        InetAddress ia=null;
        DatagramSocket ds=null; 
        String mess="你好,我想咨询一些问题。";
        //显示本地对话框
        System.out.println("我说:"+mess);
        try {
            //获取本地主机地址
            ia=InetAddress.getByName("localhost");
            //创建DatagramPacket对象,封装数据
            DatagramPacket dp=new DatagramPacket(mess.getBytes(), mess.getBytes().length,ia,8800);
            //创建DatagramSocket对象,向服务器发送数据
            ds=new DatagramSocket();
            ds.send(dp);

            System.out.println("******发送完成******");
            byte[]buf=new byte[1024];
            DatagramPacket dpre=new DatagramPacket(buf, buf.length);
            ds.receive(dpre);
            //显示接收到的信息
            String reply=new String(dpre.getData(),0,dpre.getLength());
            System.out.println(dpre.getAddress().getHostAddress()+"说:"+reply);
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            ds.close();
        }
    }
}

Stop here。But There is no end to learning!!
网络方面的东西还有很多很多。这才只是冰山一角。深入浅出吧~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值