网络编程(TCP程序、UDP程序)

1、网络编程是指多台主机之间的数据通讯操作,其要分为客户端与服务器端。在网络通讯的实现上产生的一系列处理协议:IP、TCP、UDP等。

网络程序开发的两种模型:

C/S:要开发出两套程序,一套为客户端,一套为服务器端,当服务器端发生改变后客户端也应进行更新处理。这种开发可以由开发者自定义传输协议,并且使用一些较为私密的端口,安全性较高,但是开发与维护成本较高。

B/S:只开发一套服务器端的程序,利用浏览器作为客户端进行浏览与访问,其开发与维护的成本较低(只有一套程序),但是由于其使用的是公共的HTTP协议并且使用的是公共的80端口,所以其安全性较差。现在的开发基本上以“B/S”结构为主。

网络编程主要是C/S程序模型,其分为两种开发:TCP(可靠的数据连接)与UDP(不可靠的数据连接)

2、TCP程序的基本实现

TCP的程序开发是网络程序的最基本的开发模型,其核心特点是使用两个类实现数据的交互处理:ServerSocket(服务器端)与Socket(客户端)。

ServerSocket的主要目的是设置服务器的监听端口,而Socket需要指明要连接的服务器的地址与端口。

示例:Echo的实现(客户端:键盘输入数据,将数据发送到服务器端)

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket ;
import java.net.Socket ;
import java.util.Scanner ;
//服务器端定义
public class EchoServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(9999) ; //设置服务器端的监听端口
        System.out.println("等待客户端连接...") ;
        Socket client = server.accept() ; //有客户连接
        //接收客户端发送来的消息
        Scanner scan = new Scanner(client.getInputStream()) ; //客户端输入流
        scan.useDelimiter("\n") ; //设置分隔符
        PrintStream out = new PrintStream(client.getOutputStream()) ; //客户端输出流
        boolean flag = true ; //循环标记
        while(flag) {
            if(scan.hasNext()) { //有数据
                String val = scan.next().trim() ; //接收
                if("byebye".equalsIgnoreCase(val)) {
                    out.println("byebyebye...") ;
                    flag = false ; //结束循环
                } else {
                    out.println("[Echo]" + val) ;
                }
            } 
        }
        scan.close() ;
        out.close() ;
        server.close() ;
        client.close() ;
    }
}
 

import java.io.BufferedReader ;
import java.io.InputStreamReader ;
import java.io.PrintStream;
import java.net.Socket ;
import java.util.Scanner ;
//客户端
public class EchoClient {
    private static final BufferedReader KYEBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in)) ;
    public static void main(String[] args) throws Exception {
        Socket client = new Socket("localhost",9999) ; //定义服务器的连接信息
        //客户端输出输出
        Scanner scan = new Scanner(client.getInputStream()) ; //接收服务器端的输入内容
        scan.useDelimiter("\n") ;
        PrintStream out = new PrintStream(client.getOutputStream()) ; //像服务器端发送内容
        boolean flag = true ;
        while(flag) {
            String input = getString("请输入要发送的内容:").trim() ;
            out.println(input) ; //加换行,因为服务器端以换行做的分隔符,否则服务器端找不到数据
            if(scan.hasNext()) {
                System.out.println(scan.next()) ;
            }
            if("byebye".equalsIgnoreCase(input)) {
                flag = false ;
            }
        }
        scan.close() ;
        out.close() ;
        client.close() ;
    }
    public static String getString(String prompt) throws Exception {
        System.out.println(prompt) ; //提示信息
        String str = KYEBOARD_INPUT.readLine() ; //读取键盘输入的数据
        return str ;
    }
}

程序存在的缺陷:该服务器只能为一个线程提供服务
3、多线程与网络编程

解决上述程序的缺陷:将每一个连接到服务器上的客户端都通过一个线程对象来进行处理,即服务器上启动多个线程,每一个线程单独为每一个客户端实现Echo服务支持

Echo多线程模型(BIO):

修改服务器端:

package com.demo;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket ;
import java.net.Socket ;
import java.util.Scanner ;
//服务器端定义
public class EchoServer {
    private static class ClientThread implements Runnable {
        private Socket client = null ;
        private Scanner scan = null ;
        private PrintStream out = null ;
        private boolean flag = true ;
        public ClientThread(Socket client) throws IOException {
            this.client = client ;
            //首先接收客户端发送来的消息
            this.scan = new Scanner(client.getInputStream()) ; //客户端输入流
            this.scan.useDelimiter("\n") ; //设置分隔符
            this.out = new PrintStream(client.getOutputStream()) ; //客户端输出流
            
        }
        @Override
        public void run() {
            while(this.flag) {
                if(scan.hasNext()) { //有数据
                    String val = scan.next().trim() ; //接收
                    if("byebye".equalsIgnoreCase(val)) {
                        out.println("byebyebye...") ;
                        flag = false ; //结束循环
                    } else {
                        out.println("[Echo]" + val) ;
                    }
                } 
            }
            try {
                scan.close() ;
                out.close() ;
                client.close() ;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(9999) ; //设置服务器端的监听端口
        System.out.println("等待客户端连接...") ;
        boolean flag = true ;
        while(flag) {
            Socket client = server.accept() ; //有客户连接
            new Thread(new ClientThread(client)).start() ; //将客户端请求封装到线程模型中
        }
    }
}
4、数据报发送与接收(UDP程序)

基于数据报的网络编程实现,实现UDP程序需要的两个类:DatagramPacket(数据内容)、DatagramSocket(网络发送与接收)。数据报就好比发送的短消息,客户端是否接收到与发送者无关。

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPClient {
    public static void main(String[] args) throws Exception {
        DatagramSocket client = new DatagramSocket(9999) ; //连接到9999端口
        byte data[] = new byte[2048] ; //接收消息
        DatagramPacket packet = new DatagramPacket(data,data.length) ; //接收数据
        System.out.println("客户端等待接收要发送的消息...") ;
        client.receive(packet);
        System.out.println("接收到的消息内容为:" + new String(data,0,packet.getLength())) ;
        client.close();
    }
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPServer {
    public static void main(String[] args) throws IOException {
        DatagramSocket server = new DatagramSocket(9000) ; //监听端口
        String str = "abcdefghigklmn" ;
        DatagramPacket packet = new DatagramPacket(str.getBytes(),0,str.length(),InetAddress.getByName("localhost"),9999) ;
        server.send(packet);
        System.out.println("消息发送完毕...") ;
        server.close();
    }
}

UDP发送的数据一定是不可靠的,但是TCP由于需要保证可靠的连接所以所需要的服务器资源越多。

你可能感兴趣的:(Java高级编程)