JavaSE--- 网络编程

10 网络编程

10.1 网络编程概述

    网络编程就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。

    计算机网络是指由通信线路互相连接的许多自主工作的计算机构成的集合体,各个部件之间以何种规则进行通信,就是网络模型研究的问题。网络模型一般是指OSI(Open System Interconnection 开放系统互连)七层参考模型和TCP/IP四层参考模型。

    

    网络7层模型概述

    1. 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

    2. 数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。

    3. 网络层:主要将下层接收到的数据进行IP地址(例,192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。

    4. 传输层:定义了一些传输数据的协议和端口号(WWW端口号80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层叫做段。

    5. 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接收会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接收会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。

    6. 表示层:主要是进行对接收的数据进行解释,加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够识别的东西(如图片、声音等)。表示层:主要是进行对接收的数据进行解释,加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够识别的东西(如图片、声音等)。

    7. 应用层:主要是一些终端的应用,比如说FTP(各种文件下载)、WEB(IE浏览)、QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西,就是终端应用)。

    注意:

     1、每个网卡的MAC地址都是全球唯一的。

     2、路由器实现将数据包发送到指定的地点。

     3、应用软件之间通信的过程就是层与层之间封包、解封包的过程。


    4、OSI参考模型虽然设计精细,但过于麻烦,效率不高,因此才产生了简化版的TCP/IP参考模型。

10.2 网络编程三要素

10.2.1  IP地址:InetAddress

    1. IP地址概述

    IP地址是网络中计算机的唯一标识,由网络号段和主机号段组成。由于计算机只能识别二进制的数据,所以IP地址是一个4个字节的二进制的数据,只不过为了记忆上的方便,便将每个字节分别转换成了十进制,相邻字节间用“.”分开(点分十进制)。例如:一个IP地址为:192.168.1.100,其实是11000000 10101000 00000001 01100100。

    2. IP地址分类

    A类IP地址

    A类IP地址是指, 在IP地址的四段号码中,第一段号码为网络号码,后三段号码为本地计算机的号码。地址范围:1.0.0.0-127.255.255.255。最后一个是广播地址。一个网络支持的最大主机数为256*256*256-2=16777214台。

    B类IP地址

    B类IP地址是指,在IP地址的四段号码中,前两段号码为网络号码,后两段为本地计算机的号码。地址范围:128.0.0.0-191.255.255.255。最后一个是广播地址。一个网络支持的最大主机数为256*256-2=65534台。

    C类IP地址

    C类IP地址是指,在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码。地址范围:192.0.0.0-223.255.255.255。最后一个是广播地址。一个网络支持的最大主机数为255-2=254台。

    D类IP地址

    D类IP地址在历史上被叫做多播地址(multicast address),即组播地址。在以太网中,多播地址命名了一组应该在这个网络中应用接收到一个分组的站点。多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255。

    3. IP地址类型

    公有地址:

    公有地址(Public address)由Inter NIC(Internet Network Information Center因特网信息中心)负责。这些IP地址分配给注册并向Inter NIC提出申请的组织机构。通过它直接访问因特网。

    私有地址:

    私有地址(Private address)属于非注册地址,专门为组织机构内部使用。

    以下列出留用的内部私有地址。

    A类 10.0.0.0--10.255.255.255

    B类 172.16.0.0--172.31.255.255

    C类 192.168.0.0--192.168.255.255

    

    特殊的几个IP地址:

    127.0.0.1:回环地址(表示本机)

    x.x.x.255:广播地址

    x.x.x.0:网络地址

    两个DOS命令:

    ipconfig:查看本机ip地址。

    ping:后面跟ip地址。测试本机与指定的ip地址间的通信是否有问题。

10.2.2 端口号

    端口号是用于标识进程(应用程序)的逻辑地址,不同进程的标识。

    有效端口:0~65535,其中0~1024系统使用或保留端口。

    

    PS:

    1. 当一台计算机A向另一台计算机B发送QQ信息时,首先路由器通过数据包中的IP地址定位该信息发送到哪一台机器。然后计算机B接收到数据包后,通过此数据包中的端口号定位到发送给本机的QQ应用程序。

    2. 所谓防火墙,其功能就是将发送到某程序端口的数据屏蔽掉以及将从该程序端口发出的数据也屏蔽掉。

10.2.3 传输协议

    通信的规则,常见的规则有UDP和TCP。

    UDP:

    将数据及源和目的封装成数据包中,不需要建立连接。
    每个数据报的大小在限制在64k内。
    因无连接,是不可靠协议。
    不需要建立连接,速度快。

    应用案例:QQ、FeiQ聊天、在线视频用的都是UDP传输协议。


    TCP:

    建立连接,形成传输数据的通道。
    在连接中进行大数据量传输。
    通过三次握手完成连接,是可靠协议。
    必须建立连接,效率会稍低。

    应用案例:FTP,File Transfer Protocol(文件传输协议)。

    示例:

/*
 * 如果一个类没有构造方法:
 * A:成员全部是静态的(Math,Arrays,Collections)
 * B:单例设计模式(Runtime)
 * C:类中有静态方法返回该类的对象(InetAddress) 
 * 看InetAddress的成员方法:
 * public static InetAddress getByName(String host):根据主机名或者IP地址的字符串表示得到IP地址对象
 */
public class InetAddressDemo {
	public static void main(String[] args) throws UnknownHostException {
		// public static InetAddress getByName(String host)
		InetAddress address = InetAddress.getByName("1Sad_king_PC");//Sad_king_PC

		// 获取两个东西:主机名,IP地址
		// public String getHostName()
		String name = address.getHostName();
		// public String getHostAddress()
		String ip = address.getHostAddress();
		System.out.println(name+"---"+ip);
	}
}

    运行结果:


10.3 UDP协议

10.3.1 Socket

    Socket(套接字)就是为网络服务提供的一种机制。

    Socket编程又叫网络编程、套接字编程。Socket包含了:IP地址+端口

    通信的两端都有Socket。

    网络通信其实就是Socket间的通信。

    数据在两个Socket间通过IO传输。

    

10.3.2UDP传输:

    DatagramSocket(用来发送和接收数据报包的套接字)与DatagramPacket(数据报包)。

    注意:发送端和接收端是两个独立的程序。

1. 示例:

    UDP接收端

    步骤:

    1)创建接收端Socket对象

    2)创建一个数据包(接收容器)

    3)调用Socket对象的接收方法接收数据

    4)解析数据包,并显示在控制台

    5)释放资源

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

/*
 * 多次启动接收端:
 * 		java.net.BindException: Address already in use: Cannot bind
 * 		端口被占用。
 */
public class ReceiveDemo {
	public static void main(String[] args) throws IOException {
		// 创建接收端Socket对象
		DatagramSocket ds = new DatagramSocket(12345);

		// 创建一个包裹
		byte[] bys = new byte[1024];
		// DatagramPacket(byte[] buf, int length)
		DatagramPacket dp = new DatagramPacket(bys, bys.length);

		// 接收数据
		ds.receive(dp);

		// 解析数据
		// 获取对方ip
		String ip = dp.getAddress().getHostAddress();
		String s = new String(dp.getData(), 0, dp.getLength());
		System.out.println("from " + ip + " data is:" + s);

		// 释放资源
		ds.close();
	}
}

    UDP发送端

    步骤:

    1)创建发送端Socket对象

    2)创建数据,并把数据打包

    3)调用Socket对象的发送方法发送数据包

    4)释放资源

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

public class SendDemo {
	public static void main(String[] args) throws IOException {
		// 创建发送端Socket对象
		DatagramSocket ds = new DatagramSocket();

		// 创建数据,并打包
		byte[] bys = "helloworld".getBytes();
		// DatagramPacket(byte[] buf, int length, InetAddress address, int port)
		DatagramPacket dp = new DatagramPacket(bys, bys.length,
				InetAddress.getByName("192.168.32.1"), 12345);

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

		// 释放资源
		ds.close();

	}
}

    运行结果:

2. 键盘录入数据


3.聊天


10.4 TCP传输


    客户端(Client)首先与服务端(Server)建立连接,形成通道(其实就是IO流),然后,数据就可以在通道之间进行传输,并且单个Server端可以同时与多个Client端建立连接。

10.4.1 TCP协议—基本传输

TCP客户端:

    步骤:

    1)创建发送端的Socket对象(需要明确服务器的ip地址以及端口)

    2)通过Socket对象获取输出流,写数据

    3)释放资源

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class ClientDemo {
	public static void main(String[] args) throws IOException {
		// 创建客户端的Socket对象
		// Socket(InetAddress address, int port)
		// Socket(String host, int port)
		// Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888);
		Socket s = new Socket("192.168.32.1", 8888);

		// 获取输出流,写数据
		// public OutputStream getOutputStream()
		OutputStream os = s.getOutputStream();
		os.write("hello,tcp,我来了".getBytes());

		// 释放资源
		s.close();
	}
}


TCP服务器:

    步骤:

    1)创建接收端的ServerSocket对象(需要明确它要处理的数据从哪个端口进入)

    2)监听客户端连接。返回一个对应的Socket对象

    3)通过Socket对象获取输入流,读取数据显示在控制台

    4)释放资源

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
	public static void main(String[] args) throws IOException {
		// 创建服务器的ServerSocket对象
		// ServerSocket(int port)
		ServerSocket ss = new ServerSocket(8888);

		// 监听客户端连接。返回一个对应的Socket对象
		// public Socket accept()
		Socket s = ss.accept(); // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。

		// 获取输入流,读取数据显示在控制台
		InputStream is = s.getInputStream();

		byte[] bys = new byte[1024];
		int len = is.read(bys); // 阻塞式方法
		String str = new String(bys, 0, len);

		String ip = s.getInetAddress().getHostAddress();

		System.out.println("从IP地址为:" + ip + " 传来的数据是: " + str);

		// 释放资源
		s.close();
		// ss.close(); //这个不应该关闭,因为服务器应该一直开着
	}
}

    运行结果:

客户端:


服务器:


    注意:TCP协议传输必须先运行服务器,再开客户端,否则先打开客户端会连接不上服务器

10.4.2  服务器和客户端交互

客户端:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ClientDemo {
	public static void main(String[] args) throws IOException {
		// 创建客户端Socket对象
		Socket s = new Socket("192.168.32.1", 9999);

		// 获取输出流
		OutputStream os = s.getOutputStream();
		os.write("退出界面不是太好看".getBytes());

		// 获取输入流,用来读取服务器返回的数据
		InputStream is = s.getInputStream();
		byte[] bys = new byte[1024];
		int len = is.read(bys);//阻塞
		String client = new String(bys, 0, len);
		System.out.println("从服务器返回的数据:" + client);

		// 释放资源
		s.close();
	}
}

服务端:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
	public static void main(String[] args) throws IOException {
		// 创建服务器Socket对象
		ServerSocket ss = new ServerSocket(9999);

		// 监听客户端的链接
		Socket s = ss.accept();

		// 获取输入流
		InputStream is = s.getInputStream();
		byte[] bys = new byte[1024];
		int len = is.read(bys);//阻塞
		String server = new String(bys, 0, len);
		System.out.println("从客户端传来的数据是: " + server);

		// 获取输出流,将服务器端数据反馈给客户端
		OutputStream os = s.getOutputStream();
		os.write("传送的数据已经收到".getBytes());

		// 释放资源
		s.close();
		// ss.close();

	}
}

    运行结果:



10.4.3 客户端和服务器文本转换

    需求:客户端个服务器发送文本,服务器会将文本转换成大写返回给客户端。

客户端:

package cn.itcast_08;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

/*
 * 客户端个服务器发送文本,服务器会将文本转换成大写返回给客户端。
 */
public class TransClient {
	public static void main(String[] args) throws IOException {
		// 创建客户端Socket对象
		Socket s = new Socket("192.168.32.1", 22222);

		// 封装键盘录入数据
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		// 封装通道内Socket输出流
		BufferedWriter bwOut = new BufferedWriter(new OutputStreamWriter(
				s.getOutputStream()));
		// 封装通道内输入流,用于接收服务器返回的大写字母
		BufferedReader bwIn = new BufferedReader(new InputStreamReader(
				s.getInputStream()));

		String line = null;
		while ((line = br.readLine()) != null) {
			if ("886".equals(line)) {
				break;
			}
			bwOut.write(line);
			bwOut.newLine();
			bwOut.flush();

			String upperStr = bwIn.readLine();
			System.out.println("服务器返回数据: " + upperStr);

		}

		// 释放资源
		s.close();
	}
}

服务器:

package cn.itcast_08;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TransServer {
	public static void main(String[] args) throws IOException {
		// 创建服务器ServerSocket对象
		ServerSocket ss = new ServerSocket(22222);

		// 监听客户端连接
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip + "....connected");
		// 封装通道内流
		BufferedReader brIn = new BufferedReader(new InputStreamReader(
				s.getInputStream()));
		//
		BufferedWriter bwOut = new BufferedWriter(new OutputStreamWriter(
				s.getOutputStream()));

		String line = null;
		while ((line = brIn.readLine()) != null) {
			System.out.println("客户端传入数据: " + line);
			bwOut.write(line.toUpperCase());
			bwOut.newLine();
			bwOut.flush();
		}

		// 释放资源
		s.close();
	}
}

    运行结果:


10.4.4 上传文本文件

客户端:

package cn.itcast_12;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class TextCilent {
	public static void main(String[] args) throws IOException {
		// 创建客户端Socket对象
		Socket s = new Socket("192.168.32.1", 10003);

		// 封装文本文件
		BufferedReader br = new BufferedReader(new FileReader(
				"InetAddressDemo.java"));
		// 封装通道内的输出流,用于将文本文件内容发送到服务器
		PrintWriter pwOut = new PrintWriter(s.getOutputStream(), true);

		String line = null;
		while ((line = br.readLine()) != null) {
			pwOut.println(line);
		}

		// 关闭客户端输出流,相当于给流加入标记一个技术标记
		 s.shutdownOutput();

		// 封装通道内输入流,读取从服务端返回来的数据
		BufferedReader brIn = new BufferedReader(new InputStreamReader(
				s.getInputStream()));
		String message = brIn.readLine();
		System.out.println(message);

		// 释放资源
		br.close();
		s.close();
	}
}

服务器:

package cn.itcast_12;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TextServer {
	public static void main(String[] args) throws IOException {
		// 创建服务器ServerSocket对象
		ServerSocket ss = new ServerSocket(10003);

		// 监听客户端连接
		Socket s = ss.accept();
		System.out.println(s.getInetAddress().getHostAddress()
				+ "......connected");

		// 封装通道内输入流,用来读取客户端传来的数据
		BufferedReader brIn = new BufferedReader(new InputStreamReader(
				s.getInputStream()));
		// 封装目的地文本文件
		PrintWriter pw = new PrintWriter(new FileOutputStream("Copy.java"),
				true);

		String line = null;
		while ((line = brIn.readLine()) != null) {
			pw.println(line);
		}

		// 封装通道内输出流对象,用来将服务器数据发送到客户端
		PrintWriter pwOut = new PrintWriter(s.getOutputStream(), true);
		pwOut.println("文件上传成功");

		// 释放资源
		pw.close();
		s.close();
	}
}

    运行结果:

客户端:


服务器:


10.4.5 上传图片

客户端:

package cn.itcast_13;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class ImageClient {
	public static void main(String[] args) throws IOException{
		Socket s = new Socket("192.168.32.1", 10002);

		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				"林青霞.jpg"));

		BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream()); 

		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = bis.read(bys)) != -1) {
			bos.write(bys, 0, len);
			//此处应刷新一下,将通道内的缓冲刷到服务器端的流中,如果不刷新会出现图片最后一部分缺失。
			bos.flush();
		}
		
		//告诉服务端数据已写完
		s.shutdownOutput();
		
		InputStream is = s.getInputStream();
		byte[] bys2 = new byte[1024];
		int len2 = is.read(bys2);
		System.out.println(new String(bys2, 0, len2));

		bis.close();
		s.close();

	}
}


服务器:

package cn.itcast_13;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ImageServer {
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(10002);

		Socket s = ss.accept();
		System.out.println(s.getInetAddress().getHostAddress()
				+ "....connected");

		BufferedInputStream bis = new BufferedInputStream(s.getInputStream());

		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("mm.jpg"));

		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = bis.read(bys)) != -1) {
			bos.write(bys, 0, len);
			// 此处可以不用刷新
			// bos.flush();
		}

		OutputStream os = s.getOutputStream();
		os.write("图片上传成功".getBytes());

		bos.close();
		s.close();

	}
}


    运行结果:

客户端:


服务器:


10.4.6 多个客户端上传文件



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值