网络编程基础

软件架构
C/S架构: 即Client/Server(客户端/服务器端)架构,QQ、迅雷。
B/S架构: 即Browser/Server(浏览器端/服务器端)架构,简化了系统的开发,维护和使用。谷歌、火狐。
B/S架构与C/S架构的区别:
C/S架构基于局域网的,而B/S架构基于广域网的基础上。硬件环境不同,
C/S建立在专用网络上,小范围的网络,可以专门的服务器提供数据连接和数据交换
C/S一般面向的固定用户群体,对信息的安全控制较高较高一点。
对程序架构不同用户接口不同:
C/S架构大多建立在Windows平台上,B/S建立在浏览器上,不仅可以应用在Windows平台上,也可以应用在Unix/Linux等平台上。
两种架构各有优劣,但是无论使用哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机通信的程序。

网络通信协议
网络通信协议:通信协议是计算机通信必须遵从的一种规则,协议中对数据的传输格式、传输的速率、传输的步骤等都做了统一的规定,通信双方必须同时遵守,最终实现数据的正常传输和交换。
TCP/IP:传输控制协议(TCP)/因特网互联协议(IP),他们俩定义了计算机如何联网、数据如何交换和传输的标准。它的内部包含了一系列用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫下一层所提供的协议来完成自己的请求。
协议分类
TCP协议:传输控制协议,该协议是面向连接的通信协议,即数据传输前,在发送端和接收端先建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠的无差错的数据传输。
三次握手:在数据发送的准备阶段,客户端和服务器之间通过三次交互,保证连接的可靠性。
通过三次握手,建立连接后,客户端和服务器端就可以进行数据传输了。由于这种面相连接的特性,TCP协议能够数据传输的安全。所以应用挺广泛的,下载文件等。
UDP:用户数据报协议(User DataProgram Protocal),他是一个面相无连接的协议。在进行数据传输时,不需要建立连接。不管对方在不在,直接将数据、数据源和目的地封装到数据包中,发送过去。每次发送的数据不能很大,限制在64K以内,数据有可能丢失,数据传输时不安全,速度快,QQ聊天
网络编程三要素【了解】
协议:计算机通信必须遵守的规则。
IP地址:互联网协议地址,俗称IP,IP地址用来给网络中的计算机编订一个唯一的编号。
端口号:端口号就是唯一标识设备中的进程(应用程序)。IP地址是唯一标识网络中的设备。
网络编程三要素
协议:计算机中网络通信必须遵守的规则。
IP地址:互联网协议地址(Internet Protocol Address) ,俗称IP,给网络中的计算机设备编订一个唯一的编号,好比人的身份证号。

IP地址分类:
IPv4:是一个32位的二进制数,通常被分为4个字节,表示形式:a.b.c.d ,例如:192.168.53.245 ,其中a.b.c.d都是一个0~255之间的十进制的整数,那么最多能够表示42亿个。
IPv6:为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节分为一组,分成8组十六进制数 ,表示形式:ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称互联网中的任何一粒沙子能够编写进去,解决了地址不够的问题。
通过DOS命名查看本机的IP地址:ipconfig
检查网络连接是否正常:ping ip
地址特殊的IP地址:
本机的IP地址:127.0.0.1 localhost 通过hosts文件,可以自定义自己的域名
端口号:如何区分在网络通信中打开的这些进程(应用程序)?通过端口号可以准确的找到彼此。
端口号:用两个字节表示的整数,它的取值范围是0~65535。 其中,0~1023之间的的端口号被一些知名的应用和网络服务占用了。普通的常规的应用程序只能使用从1024以上的端口号, 如果端口号被另外一个服务或者应用程序占用了,会导致当前程序启动失败。
常用的端口号:
Tomcat应用服务器:8080
HTTP服务器:80 www.baidu.com:80 80端口可以选择省略不写
数据库服务器:MYSQL:3306 Oracle:1521
TCP通信
目的:实现两台计算机之间的交互,通信两端要严格区分客户端和服务器端口
两端通信的步骤:

  1. 服务端需要启动,等待客户端链接
  2. 客户端需要主动地链接服务器端,链接成功才能通信,服务器端口不可以主动链接客户端

在java中,提供两个类,实现TCP通信:

  • 客户端:创建Socket对象,创建之后就相当于创建了客户端,向服务器端发送链接请求,服务器端回响一个请求表示已经接受,两者就建立了通信
  • 服务器端:创建ServerSocket对象,创建之后就相当于,开启了一个服务,等待客户端链接
    Socket类
    Socket类,实现客户端套接字,套接字指的是两台设备之间通讯的端点,
    构造方法:
    public Socket(String host,int port);—>创建套接字对象并连接到指定主机的指定端口号,如果指定了host是一个null,那么就相当于与指定地址为回送地址【127.x.x.x】,是本机的回送地址,主要用于网络软件测试使用,本机上进程间的通信。就不会进行网络传输
    成员方法:
  • public InputStream getInputStream();---->获取套接字的输入流
  • public OutputStream getOutputStream();—>获取套接字输出流
  • public void close();—>关闭套接字
  • public void shoutdownOutput();—>禁用套接字输出流
  • 任何先前写入的数据都将会被发送,最后终止输出流
    ServerSocket类
    ServerSocket类实现了服务器端套接字,该对象等待通过网络的请求
    构造方法:
    ServerSocket(int port);—>使用该构造方法子创建ServerSocket创建对象时,就可以将其绑定到一个指定的端口号上面,参数port就是端口号
    成员方法:
    public Socket accept();—>监听并接受连接,返回一个新的Socket对象,用于和用户端实现通信。
    代码示例
    服务器端:
/*
   服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据
   服务器端的实现步骤:
       1. 创建ServerSocket服务器端对象和系统指定的端口号
       2. 使用ServerSocket对象中的方法accept,获取客户端请求的连接,拿到Socket对象
       3. 使用Socket对象中的方法getInputStream(),可以获取网络字节输入流对象
       4. 使用网络字节输入流对象中的方法read,读取客户端发送的数据
       5. 使用Socket对象中的方法getOutputStream(),获取网络字节输出流对象
       6. 使用网络字节输出流对象中的方法write,给客户端回写数据
       7. 释放资源(ServerSocket,Socket)
   服务器端必须明确到底是哪一个客户端给你发送的请求
   可以使用accept方法来获取到客户端对象Socket
   通过accept方法来监听接收此套接字的连接。
 */
 public static void main(String[] args) throws IOException {
        //1. 创建ServerSocket服务器端对象和系统指定的端口号
        ServerSocket server = new ServerSocket(6666);
        //2. 使用ServerSocket对象中的方法accept,获取客户端请求的连接,拿到Socket对象
        Socket socket = server.accept();
        //3. 使用Socket对象中的方法getInputStream(),可以获取网络字节输入流对象
        InputStream is = socket.getInputStream();
        //4. 使用网络字节输入流对象中的方法read,读取客户端发送的数据
        byte[] bytes = new byte[1024];
        int len = is.read(bytes);//
        // 打印接收客户端发送的数据
        System.out.println(new String(bytes,0,len));
        //5. 使用Socket对象中的方法getOutputStream(),获取网络字节输出流对象
        OutputStream os = socket.getOutputStream();
        //6. 使用网络字节输出流对象中的方法write,给客户端回写数据
        os.write("我收到了你的请求消息".getBytes());
        //7. 释放资源(ServerSocket,Socket)
        socket.close();
        server.close();
    }

客户端:

/*
    实现步骤:
         1. 创建一个Socket客户端对象,构造方法中绑定服务器的ip地址和端口号
         2. 使用Socket对象中的方法getOutputStream获取网络字节输出流对象
         3. 使用网络字节输出流对象中的方法write,给服务器发送数据
         4. 使用Socket对象中的方法getInputStream()获取网络字节输入流对象
         5. 使用网络字节输入流对象调用read方法,读取服务器回写的数据
         6. 释放资源(Socket)
   java.net.ConnectException: Connection refused: connect
   注意事项:
        1. 客户端和服务端进行交互的时候,必须使用Socket中提供的网络流,不能使用创建的流对象
        2. 当我们创建客户端对象Socket的时候,就会去请求服务器和服务器进行三次握手建立网络连接
           这时如果服务器端没有启动,那么程序就会抛出 java.net.ConnectException: Connection refused: connect
           如果服务器启动了,那么就可以进行交互。
 */
 public static void main(String[] args) throws IOException {
        // 1. 创建一个Socket客户端对象,构造方法中绑定服务器的ip地址和端口号
        Socket socket = new Socket("127.0.0.1", 6666);
        // 2. 使用Socket对象中的方法getOutputStream获取网络字节输出流对象
        OutputStream os = socket.getOutputStream();
        // 3. 使用网络字节输出流对象中的方法write,给服务器发送数据
        os.write("你在干什么".getBytes());
        // 4. 使用Socket对象中的方法getInputStream()获取网络字节输入流对象
        InputStream is = socket.getInputStream();
        // 5. 使用网络字节输入流对象调用read方法,读取服务器回写的数据
        byte[] bytes = new byte[1024];
        int len = is.read(bytes);// 有效字节个数
        // 打印下服务器回传的数据
        System.out.println(new String(bytes,0,len));
        // 6. 释放资源
        socket.close();
    }

文件上传案例:
步骤:
1.在客户端当中,通过输入流,从硬盘当中读取文件数据到内存
2.在客户端当中,通过输出流,写入文件数据到服务器端中
3.在服务器端中,通过输入流,读取文件数据到服务器端中
4.在服务器端中,通过输出流,写入文件数据到服务器硬盘当中

服务器端:

public static void main(String[] args) throws IOException {
        // 1. 创建一个服务器端ServerSocket
        ServerSocket server = new ServerSocket(9999);
        // 2. 使用serverSocket对象中的方法accept,获取客户端Socket对象
        Socket socket = server.accept();
        // 3. 通过socket对象获取网络字节输入流
        InputStream is = socket.getInputStream();
        // 4. 判断文件夹是否存在
        File file = new File("E:\\documents\\day31_Net");
        if (!file.exists()) {
            file.mkdirs();
        }
        // 5. 创建一个本地的文件字节输出流对象,构造方法绑定输出的目的地
        FileOutputStream fos = new FileOutputStream(file + "\\3.gif");
        // 6. 通过网络字节输入流读取客户端发送的数据,再次通过本地的字节输出流写入文件中
        int len = 0;// 记录读取的有效的字节个数
        byte[] bytes = new byte[1024];
        while ((len = is.read(bytes)) != -1) {
            //通过write方法写入本地的文件中
            fos.write(bytes,0,len);
        }
        // 7. 释放资源
        fos.close();
        socket.close();
        server.close();
    }

客户端:

public static void main(String[] args) throws IOException {
        // 1. 先创建一个本地的字节输入流,绑定读取的数据源
        FileInputStream fis = new FileInputStream("C:\\Users\\admin\\Desktop\\3.gif");
        // 2. 创建一个网络字节输出流 往服务器发送数据
        // 2.1 构建一个Socket客户端对象
        Socket socket = new Socket("127.0.0.1", 9999);
        // 2.2 从socket对象中获取网络字节输出流
        OutputStream os = socket.getOutputStream();
        // 2.3 通过本地字节输入流读取数据,再通过网络字节数输出流发送给服务器端
        byte[] bytes = new byte[1024];
        int len = 0;// 记录读取的有效字节个数
        while ((len = fis.read(bytes)) != -1) {
            // 调用write方法发送数据
            os.write(bytes, 0, len);
        }
        // 释放资源
        socket.close();
    }

文件下载案例
服务器端:

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("E:\\3.gif\\文件上传.png");
        ServerSocket server = new ServerSocket(9999);
        Socket socket = server.accept();
        OutputStream os = socket.getOutputStream();
        byte[] bytes = new byte[1024];
        int len=0;
        while ((len=fis.read(bytes))!=-1){
            os.write(bytes,0,len);
        }
        os.close();
        socket.close();
        fis.close();
    }

客户端:

public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",9999);
        InputStream is = socket.getInputStream();
        File file = new File("C:\\Users\\99213\\Desktop\\下载地址");
        if(!file.exists()){
            file.mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(file + "\\下载副本.png");
        int len=0;
        byte[] bytes = new byte[1024];
        while ((len=is.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
        fos.close();
        is.close();
        socket.close();
    }

文件上传优化
文件名称需要优化
服务端,保存文件时如果名称固定,那么最终会导致服务器硬盘,只会保留一个文件,对上传的文件名称优化。

//文件名称定义规则:
"beautiful" + System.currentTimeMillis() + new Random().nextInt(1000000) + ".jpg";

服务器端接收文件的优化
服务器端,接收一个文件之后就关闭了,后面的其他客户端无法继续上传文件,使用循环进行改进,可以不断的接收不同的客户端传输过来的文件。

// 使用循环
while(true) {
   Socket socket =  serverSocket.accept(); 
   ....
   ....       
}

服务器端接收客户端文件的效率的优化
服务器端,在接收文件的时候,加入某个客户端给你传输一个大文件,此时就不能再接收其他用户的文件,所以可以用多线程技术优化接收效率。

while(true) {
      Socket socket = serverSocket.accept();
      // 使用多线程技术,提高程序的效率
      // 有一个客户端上传文件,就开启一个线程,完成文件的上传
     new Thread(new Runnable() {
         // 重写run方法,设定线程的任务
         @Override
         public void run() {
             // 使用网络字节输入流对象
            InputStream is =  socket.getInputStream();
            // 指定一个目录
           File file =  new File("D:\\upload");
             if(!file.exits()) {
                 file.mkdirs();
             }
             // 防止同名的文件被覆盖
         String filename =  "beautiful" + System.currentTimeMillis() + new Random().nextInt(1000000) + ".jpg";  
           // 构建一个本地的文件字节输出流对象
             new FileOutputStream(file + "\\" + filename);
           // 一读一写完成文件的上传,最终把文件写入到服务器端的硬盘当中。  
          .....  
         }
     }).start();
}
// 服务端不关闭
// serverSocket.close();
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值