17.网络编程

网络编程

1.网络概述

1.1 IP地址

唯一标识网络上的每一台计算机

组成:4个8位二进制数组成

IP地址 = 网络地址 + 主机地址

c类前8位:192~223

1.2 DNS域名解析

由域名解析为ip地址

1.3网络通信协议(互联网协议/五层协议体系结构)

为了在网络中不同的计算机之间进行通信而建立的规则、标准或约定的集合

网络体系结构:

应用层(HTTP等)、传输层(TCP、UDP)、网络层、数据链路层、物理层

2.Socket(套接字)简介

意思:套接字

基于字节流实现

输出流必须使用字节流相关的实现,如对象输出流。

输入流首次获取是使用字节流,可嵌套为其他流!!!

Socket是应用层与TCP/IP协议通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket:通信链路的端点就被称为“套接字”(英文名Socket),是提供给应用程序的接口

面试题: TCP与UDP的区别

  • TCP:面向连接 可靠的传输服务 传输较慢 数据传输没有大小限制

  • UDP:面向无连接 不可靠的传输服务 传输较快 每一个数据包有大小限制,要求在64KB以内

TCP特征:

1. TCP协议是完全依赖IO流的,面向连接的!!!
  1. 数据传输没有大小限制

  2. 因为面向连接,所以数据安全

  3. 因为面向连接,所以速度较慢

  4. TCP协议严格区别客户端和服务器

UDP协议下的socket:

1. 是按照数据包的方式来处理数据,面向无连接。
  1. 每一个数据包有大小限制,要求在64KB以内!

  2. 因为面向无连接,所有传输数据不安全,不稳定

  3. 因为面向无连接,所有传输速度贼快

  4. UDP不区分客户端和服务器,只有发送端和接收端

 TCPUDP
是否连接面向连接面向非连接
传输可靠性可靠不可靠
速度

2.1基于TCP协议的Socket编程

特点:

  • 面向连接的 可靠 安全的传输协议

TCP的连接和断开涉及三次握手和四次挥手

软件的分类:

  • B/S Browser Server 基于浏览器的软件,代码编写相对简单 因为我们只需要编写一套代码发布与服务器就可以

  • C/S Client Server 基于客户端的软件,因为我们要两套程序 一个客户端 一个服务器 维护难度

输出流必须使用字节流相关的实现,如对象输出流。

输入流首次获取是使用字节流,可嵌套为其他流!!!

客户端实现步骤:

1.创建Socket实例(地址和端口号)

2.通过Socket实例获取字节输出流,必须使用字节流

3.使用字节流输出(支持byte数组与int,也可使用String类型转byte)

4.关闭此Socket输出流(socket.shutdownOutput) //

必须关闭输出流(面向连接的,不关闭,对方不知道何时接收),而输入流无所谓

5.关闭资源(finally中)

/**
 *  客户端
 * @author asus
 *
 */
public class Client {
    public static void main(String[] args) {
        try {
            // 地址就写当前电脑的ip地址  
            // 本机的ip地址  localhost  等价  127.0.0.1 
            Socket socket = new Socket("localhost", 8899);
            System.out.println("客户端准备就绪。。。。。。");
            OutputStream os = socket.getOutputStream();
            os.write("服务器你好,睡了吗?".getBytes());
            socket.shutdownOutput(); // 关闭写入 输出流 
            
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            System.out.println("好激动,服务器回话了" + br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭资源
    }
}

服务端实现步骤:

1.创建ServerSocket实例(服务器端口号)

2.调用accept方法 程序阻塞 等待客户端连接,返回一个Socket

3.通过socket获取字节输入流,也可转换成字符流/缓冲流等

4.关闭资源


/**
*   服务端
* @author asus
*
*/
public class Server {
    public static void main(String[] args) {
        // 通过ServerSocket 创建一个服务器Socket
        // 端口号 表示每一个应用程序唯一的编号  
        // 一些应用程序有默认的端口号 比如 tomcat 8080 mysql 3306 
        // 端口号取值范围 0~ 65535  我们在定义端口号的时候  9000以上都可以使用 
        
        try {
            ServerSocket ss  = new ServerSocket(8899);
            System.out.println("服务器启动完毕,等待连接。。。。。");
            Socket socket = ss.accept(); // 此时调用accept方法 程序将会阻塞 等待客户端连接
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info = br.readLine();
            System.out.println("客户端发送的信息是:" + info );       
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭资源
    }
}

2.2基于TCP实现对象的传递

对象实例化,实现serializable接口

客户端:将字节输出流转换成对象输出流,其仍属于字节流

服务器:将字节输入流转换成对象输入流

public class Client {
    public static void main(String[] args) {
        System.out.println("客户端就绪。。。");
        try {
            Socket socket = new Socket("localhost", 9998);
            OutputStream os = socket.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(new Student("艺博", 180));
            socket.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
​
public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(9998);
            System.out.println("服务器就绪。。。");
            Socket socket = ss.accept();
            InputStream is = socket.getInputStream();
            ObjectInputStream ois = new ObjectInputStream(is);
            Student student =  (Student) ois.readObject();
            socket.shutdownInput();
            System.out.println(student);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

​public class Student implements Serializable{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }   
}

2.3基于TCP实现多线程处理请求

1.服务器必须处于开启状态,使用死循环

2.业务处理代码放入线程类run方法中

3.可以使用多个线程分别回应客户端,在服务器端创建线程实例

//Client2,Client3与Client1代码相同
​
/**
*   模拟多个客户端访问服务器 服务器 一一回应 
* @author asus
*
*/
public class Client1 {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8899);
            OutputStream os = socket.getOutputStream();
            os.write("服务器你好,我是1号客户端".getBytes());
            socket.shutdownOutput();
            
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while(( line =br.readLine()) != null) {
                System.out.println("服务器回话了:" + line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭资源
        }
    }
}
/**
* 	服务器
* 	因为目前是三个客户端来访问 所以我们要
* 	1.服务器必须一值处于开启状态
* 	2.可以使用多个线程来分别回应客户端
* @author asus
*
*/
public class Server {
	public static void main(String[] args) {
		try {
			ServerSocket ss = new ServerSocket(8899);
			System.out.println("服务器启动……");
			while(true) {
				Socket socket  = ss.accept(); // 不同的客户端请求访问 返回的是不同的socket 
				// 执行完以上代码 程序继续 服务器将停止 所以我们编写一个线程类 代替服务器应答
			
				new ServerThread(socket).start();;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

/**
* 	当前了你作为服务器应答的线程类
* 	如何区分不同的请求?
* 	通过Socket 本类中声明一个属性 Socket
* 	这个Socket将作为run方法中回应客户端的重要依据
*/
public class ServerThread extends Thread{
	private Socket socket;

	public Socket getSocket() {
		return socket;
	}
	public void setSocket(Socket socket) {
		this.socket = socket;
	}
	public ServerThread(Socket socket) {
		this.socket = socket;
	}
	
	@Override
		public void run() {
			try {
				InputStream is = this.socket.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(is));
				String line = null;
				while(( line =br.readLine()) != null) {
					System.out.println("客户端说的话: " + line);
				}
				
				OutputStream os = socket.getOutputStream();
				os.write("客户端你好,睡了".getBytes());
				socket.shutdownOutput();
				
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}	
}

2.4基于UDP的Socket编程

UDP 用户数据报协议 报文 非面向连接 不安全 不可靠 效率高

步骤:

1.利用DatagramPacket对象封装数据包,创建实例

2.用DatagramSocket发送或接受数据,send/receive

/**
* 	UDP 用户数据报协议 报文  数据包  
* 	非面向连接 不安全 不可靠 效率高
* @author asus
*
*/
public class Client {
	public static void main(String[] args) {
		String info = "hello 服务器";
		System.out.println("客户端准备发送信息……");
		byte [] datas = info.getBytes();
		InetAddress localHost;
		try {
			localHost = InetAddress.getLocalHost();
			// 1 发送的内容 ---包裹内容
			// 2 内容大小   --- 包裹的重量
			// 3 地址   --- 地址
			// 4 端口号 --- 联系方式
			DatagramPacket dp = new DatagramPacket(datas, datas.length, localHost, 8899);
			// 创建DatagramSocket 对象用于发送数据
			DatagramSocket ds = new DatagramSocket();
			ds.send(dp); // 通过send方法将打包好的内容发送
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
/**
* 	服务器
* @author asus
*
*/
public class Server {
	public static void main(String[] args) {
		try {
			DatagramSocket ds =  new DatagramSocket(8899);
			System.out.println("服务器启动……");
			byte [] bag = new byte[1024];
			// 1 接收内容用的byte数组  --- 准备装快递包裹
			// 2 数组的长度    --- 包裹大小
			DatagramPacket dp = new DatagramPacket(bag, bag.length);
			ds.receive(dp); // 接收包裹
			// 拆快递的过程  
			System.out.println(new String(dp.getData(),0,dp.getData().length));
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

3. InetAddress

概念:表示互联网协议(IP)地址对象,封装了与该IP地址相关的所有信息,并提供获取信息的常用方法

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值