Java网络编程

Java网络编程

一.InetAddress类

此类没有构造方法,表示互联网协议 (IP) 地址。

如果一个类中没有构造方法:
  A:这个类里面的成员方法都是静态(Math,Arrays,Collections)
  B:单例模式:在内存始终只有一个对象
  将构造方法私有化
  在成员变量创建该类的实例(并且这个实例私有化被static修身)
  提供该类公共方法可以通过外界调用
 C:该类中会有某些静态成员方法的返回值是该类本身(InetAddress)


常用方法:
public static InetAddress getByName(String host)throws UnknownHostException在给定主机名的情况下确定主机的 IP 地址
public String getHostName()获取此 IP 地址的主机名。 
public String getHostAddress()返回 IP 地址字符串
import java.io.IOException;
import java.net.InetAddress;

public class Demo {

	public static void main(String[] args) throws IOException {
		//获取IP地址
		InetAddress address = InetAddress.getByName("DESKTOP-FN4C53P");
		System.out.println(address.getHostAddress());//172.19.25.233
		//获取主机名
		String name = address.getHostName();
		System.out.println(name);//DESKTOP-FN4C53P
	}
}


二.网络编程的三要素

1)找到IP地址
2)必须有端口
3)必须有协议(TCP协议,UDP协议)



IP地址:

PC机器都有唯一的标识:ip
常见的IP:
A类:1.0.0.1---127.255.255.254:第一个号段为网络号段,后三个号段为主机号段

B类:128.0.0.1---191.255.255.254:前两个号段为网络号段,后两个号段为主机号段()

C类:192.0.0.1---223.255.255.254:前三个好号段为网络号段,后一个号段为主机号段


D类 224.0.0.1---239.255.255.254
E类 240.0.0.1---247.255.255.254
127.0.0.1:回环地址(也可表示本机地址)
xxx.xxx.xxx.255:广播地址

常用的命令:
ipconfig:查看ip
ping ip地址:查看当前本机与这台PC机器的网络通信  



端口: 
如果一台机器想要和另一台进行通信的话,光有ip是不行的,还必须知道端口号是多少

有效端口号:0~65535
保留端口号:0~1024

    
 
协议:
TCP协议和UDP协议 

TCP协议:(客户端和服务器端的交互)
1)建立连接通道(通道内的流:(使用的是最基本的字节流))
2)可靠协议
3)由于可靠协议,并且需要建立连接通道(服务器端需要等待客户端连接),执行效率低
4)使用TCP协议(TCP编程)可以发送大量的数据,文件大小无限制

UDP协议:(发送端和接收端)
1)无需建立连接通道(数据报包的形式发送数据的)
2)不可靠协议
3)由于不可靠,无需建立连接通道,所以它的执行效率高
4)UDP协议(UDP编程)发送数据有限制  


Socket()对象:


public class Socket
extends Object
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。

三. UDP协议

UDP发送端  :
1)创建UDP协议发送端的Socket对象
  2)创建数据报包:通过这个数据包将数据发送到接收端
  3)调用UDP协议发送端发送的方法
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 {
		
		//public DatagramSocket() throws SocketException
		//创建Socket()对象
		DatagramSocket ds = new DatagramSocket();
		//创建数据报包
		byte [] bys = "原谅我这一生放浪不羁爱自由..".getBytes();
		DatagramPacket dp = new DatagramPacket(bys, bys.length,
				InetAddress.getByName("127.0.0.1"),12345);
		
		//将数据以数据报包的形式发出去
		ds.send(dp);
		//关闭资源
		ds.close();
	}
}




 UDP协议的接收端
  
  1)创建接收端的Socket对象
  2)创建一个数据报包接收发送端发送来的数据报包(接收容器)
  3)接收数据,调用DataScoket类中的接收的方法来接收数据包
  4)解析数据报包里面的实际数据,显示在控制台上
  5)关闭资源
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo {

	public static void main(String[] args) throws IOException {	
		
		//创建接收端的Socket对象
		DatagramSocket ds = new DatagramSocket(12345);
		
		//创建一个接收容器接收数据
		byte [] bys = new byte[1024];
		DatagramPacket dp = new DatagramPacket(bys, bys.length);
		
		//接收数据
		ds.receive(dp);
		
		//解析数据并显示在控制台
		String ip = dp.getAddress().getHostAddress();
		//获取缓存区中的实际数据
		byte[] bys2 = dp.getData() ;
		//获取实际缓冲区数据的长度
		int len = dp.getLength();
		String s = new String(bys2, 0, len);
		//输出在控制台
		System.out.println(ip+"传递的数据是:"+s);
				
		//关闭资源
		ds.close() ;
	}
}
 练习:发送端的数据来源不是简单的一条语句而是不停的键盘录入
  
  键盘录入的方式:
   1)Scanner类
   2)BufferedReader类(字符缓冲流)特有功能:readLine():一次读取一行    (System.in)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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();
		//创建键盘录入,以IO流的形式
		BufferedReader br = new BufferedReader(
				new InputStreamReader(System.in));
		String line = null;
		while((line = br.readLine()) != null) {
			if("over".equals(line)) {
				break;
			}

			//创建数据报包
			byte[] bys = line.getBytes();
			DatagramPacket dp = new DatagramPacket(bys, bys.length,
					InetAddress.getByName("127.0.0.1"),12345);
			
			//发送数据
			ds.send(dp);
		}
		//释放资源
		ds.close();
	}
}
接受端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo {

	public static void main(String[] args) throws IOException {
		//创建接收端的socket对象
		DatagramSocket ds = new DatagramSocket(12345);
		
		while(true) {
			byte [] bys = new byte[1024];
			DatagramPacket dp = new DatagramPacket(bys, bys.length);
			//接收数据
			ds.receive(dp);
			String ip = dp.getAddress().getHostAddress();
			
			//解析数据接收容器,获取里面实际的内容
			byte[] data = dp.getData();
			int len = dp.getLength();
			String s = new String(data, 0, len);
			//显示到控制台
			System.out.println("form"+ip+"Data is :"+s);
		}
		
	}
}


四.TCP协议:

客户端步骤:
  1)创建客户端的socket对象 (客户端套接字流的形式)
  2)获取通道的内流(输出流)
  3)使用输出流对象写数据
   4)关闭客户端的Socket对象
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 使用Socket编程里面的TCP协议
 * 客户端和服务器端的交互
 * 客户端步骤:
 * 	1)创建客户端的socket对象 (客户端套接字流的形式)
 * 	2)获取通道的内流(输出流)
 * 	3)使用输出流对象写数据
 * 	4)关闭客户端的Socket对象
 *
 * */
public class ClientDemo {

	public static void main(String[] args) throws IOException {
		//1)创建客户端的socket对象:此类实现客户端套接字
		Socket s = new Socket("172.19.25.233",10000);
		/*InetAddress address = InetAddress.getByName("DESKTOP-FN4C53P");
		System.out.println(address.getHostAddress());*/
		//2)获取通道的内流(输出流)
		OutputStream os = s.getOutputStream();
		//3)客户端通道内的流给服务器写数据
		os.write("爱恨情仇都付谈笑".getBytes());
		//4)关闭客户端socket
		s.close();
	}
}
TCP协议的服务器端
  
  1)创建服务器端的socket对象,指定端口
  2)服务器端需要监听客户端的连接
  3)获取通道内的输入流
  4)将数据获取到并显示到控制台
  5)关闭服务器端的socket资源
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *  TCP协议的服务器端
 * 
 * 1)创建服务器端的socket对象,指定端口
 * 2)服务器端需要监听客户端的连接
 * 3)获取通道内的输入流
 * 4)将数据获取到并显示到控制台
 * 5)关闭服务器端的socket资源
 *
 * */
public class ServerDemo {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		//public ServerSocket(int port) 构造方法:创建绑定到特定端口的服务器套接字
		ServerSocket ss = new ServerSocket(10000);
		System.out.println("等待客户端连接...");
		//2)监听客户端的连接:public Socket accept()请求等待介入
		Socket s = ss.accept();	
		System.out.println("客户端已连接...");
		//3)获取通道内的输入流
		InputStream in = s.getInputStream();
		//4)将数据获取到并显示到控制台
		//定义一个缓冲数组
		byte[] bys = new byte[1024];
		int len = in.read(bys);
		String str = new String(bys, 0, len);
		//获取IP地址的文本形式
		InetAddress address = s.getInetAddress();
		String ip = address.getHostAddress();
		System.out.println(ip+"传递的数据是:"+str);
		
		s.close();
	}
}

客户端发送数据,服务器端给客户端反馈数据
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("172.19.25.233",12580);
		//获取通道内的输出流
		OutputStream os = s.getOutputStream();
		
		os.write("上元溪旁点烛荷  千盏承诺".getBytes());
		//获取通道内内的输入流对象
		InputStream in = s.getInputStream();
		byte [] bys = new byte[1024];
		int len = in.read(bys);
		String str = new String(bys, 0, len);
		System.out.println("clinet:"+str);
		
		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 {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		//1)创建服务器端的socket对象
		ServerSocket ss = new ServerSocket(12580);
		System.out.println("等待客户端连接...");
		Socket s = ss.accept();
		System.out.println("客户端已连接....");
		InputStream in = s.getInputStream();
		
		byte[] bys2 = new byte [1024];
		int len2 = in.read(bys2);
		String server = new String(bys2, 0, len2);
		//输出客户端给服务器端发送的数据
		System.out.println("server:"+server);
		//服务器端反馈
		OutputStream out= s.getOutputStream();
		out.write("[自动回复]:您好,我现在有事,不方便回复!".getBytes());
		//关闭资源
		s.close();
	}
}

需求:客户端键盘录入数据,服务器端将数据显示控制台
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 ClientDemo {

	public static void main(String[] args) throws IOException {
		
		Socket s = new Socket("172.19.25.233",11000);
		//BufferedReader字符流封装数据,读取键盘录入的数据
		BufferedReader br = new BufferedReader(
				new InputStreamReader(System.in));
		//使用字符缓冲输出流封装通道内的流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		//利用BufferedReader一次读取一行数据:readLine
		String line = null;
		while((line = br.readLine()) != null) {
			//结束条件
			if("over".equals(line)) {
				break;
			}
			bw.write(line);
			bw.newLine();
			bw.flush();		
		}
		//关闭资源
		s.close() ;
	}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

	public static void main(String[] args) throws IOException {
		//1)创建服务器端的Socket对象
		ServerSocket ss = new ServerSocket(11000);
		System.out.println("等待服务器连接...");
		//2)监听客户端的连接
		Socket s = ss.accept();
		System.out.println("服务器已连接...");
		//3)封装服务器通道内的流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		String line = null;
		while((line = br.readLine()) != null) {
			System.out.println(line);
		}
		//关闭资源
		s.close();
	}
}
客户端键盘录入,服务器输出将录入的内容输出到文本文件
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 ClientDemo {

	public static void main(String[] args) throws IOException {
		
		Socket s = new Socket("127.0.0.1",6666);
		
		//键盘录入:IO流的形式
		BufferedReader br = new BufferedReader(
				new InputStreamReader(System.in));
		//封装通道内的流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		
		String line = null;
		while((line = br.readLine()) != null) {
			if("over".equals(line)) {
				break;
			}
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		//释放资源
		s.close();
	}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {

	public static void main(String[] args) throws IOException {
		//创建服务器端的Socket对象
		ServerSocket ss = new ServerSocket(6666);
		//监听客户端连接
		Socket s = ss.accept();
		//封装通道内的流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		//服务器端输出一个文本文件
		BufferedWriter bw = new BufferedWriter(
				new FileWriter("a.txt"));
		//服务器端通道内的流读取客户端发送的数据,将数据一次写入到a.txt文件中
		String line = null;
		while((line = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}	
		s.close();
		bw.close();
	}
}

需求:客户端一个文本文件,服务器端将客户端文本文件中的内容展示到控制台上
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ClientDemo {

	public static void main(String[] args) throws  IOException {
		//创建客户端的Socket对象
		Socket s = new Socket("127.0.0.1",12345);
		//封装文本文件
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		//封装通道内的流:将字节输出流封装成字符缓冲输出流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		//将文本文件中的数据写入到被封装的通道内的流中
		String line = null;
		while((line = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		//释放资源
		br.close();
		s.close();
	}
}

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

public class ServerDemo {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		
		//创建服务器端Socket()对象
		ServerSocket ss = new ServerSocket(12345);
		//监听客户端
		Socket s = ss.accept();
		//封装通道内的流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		//读取一行数据,就展示到控制台上
		String line = null;
		while((line = br.readLine()) != null) {
			System.out.println(line);
		}
		//释放资源
		s.close();		
	}
}

客户端文本文件,服务器端将文本文件中的内容复制输出到一个新的文本文件中 

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

public class UploadClient {

	public static void main(String[] args) throws IOException {
		//创建客户端的socket对象
		Socket s = new Socket("127.0.0.1",12580);
		//封装文件
		@SuppressWarnings("resource")
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		
		//封装通道内字节输出流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		
		//一次读取一行
		String line = null;
		while((line = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		//释放资源
		s.close();
	}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadServer {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		//创建服务器端的Socket()对象
		ServerSocket ss = new ServerSocket(12580);
		//监听客户端
		Socket s = ss.accept();
		//封装通道内的流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		//服务器端要将输出文本文件进行复制
		BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
		//一次读取一行
		String line = null;
		while((line = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		//释放资源
		s.close();
		bw.close();
	}
}

客户端文本文件,服务器端将文本文件中的内容复制输出到一个新的文本文件中,并且服务器端反馈给客户端,文件复制成功了...

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

public class UploadClient {

	public static void main(String[] args) throws IOException {
		
		Socket s = new Socket("127.0.0.1",12345);
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		//封装通道内的流
		BufferedWriter bw = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		//一次读取一行
		String line = null ; 
		while((line = br.readLine()) != null) {
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		
		/*//方案一:定义一个结束标记
		bw.write("over");
		bw.newLine();
		bw.flush();*/
		
		//方案二通过这个方法告诉服务器端,客户端这边没数据了,读完了,你反馈
		s.shutdownOutput();
		//读取服务器端的反馈
		//获取通道内的输入流对象
		BufferedReader brClient = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		
		//读数据
		String fk = brClient.readLine();
		System.out.println(fk);
		//释放资源
		s.close();
		br.close();
	}
}

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

public class UploadServer {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		
		//创建服务器端的socket对象
		ServerSocket ss = new ServerSocket(12345);	
		//监听客户端连接
		Socket s = ss.accept();
		
		//封装通道内的流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		
		BufferedWriter bw = new BufferedWriter(new FileWriter("copy2.txt"));
		
		
		String line = null;
		while((line = br.readLine()) != null) {//读到的null的情况,文件读完毕  ,阻塞
			/*if("over".equals(line)) {
				break;
			}*/
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		//反馈:获取通道内的输出流对象,并且用BufferedWrite封装
		BufferedWriter bwServer = new BufferedWriter(
				new OutputStreamWriter(s.getOutputStream()));
		bwServer.write("文件复制完毕....");
		bwServer.newLine();
		bwServer.flush();
		
		//释放资源
		s.close();
		bw.close();
	}
}

注意:按照正常的逻辑操作写完了客户端和服务器的需求,运行的时候,发现都处于等待情况,是什么原因呢?
对于客户端来说,它要将java文件写入到字符输出流中(通道内的流),在最终返回如果是null(null在网络编程中是不能作为结束条件的)的情况下,文件读完了,但是服务器端不指定
  客户端这边java文件是否读完了,两端readLine都处于阻塞,如何解决?
  
  方案1:在客户端这边定义结束标记,服务器端只要读到结束标记了,就表示读完了.
   该方式虽然可以,但是可能文件中有某句话就是自定义结束语句,可能文件压根没有读完就结束了!,不够好!
  
  方案2:public void shutdownOutput()   throws IOException禁用此套接字的输出流

客户端的图片文件,服务器端输出一个图片文件并且给出反馈

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 UploadClient {

	public static void main(String[] args) throws IOException {
		
		Socket s = new Socket("127.0.0.1",6666);
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream("D:\\壁纸.jpg"));
		//获取通道内的流 输出流 OutputStream
		BufferedOutputStream bos = new BufferedOutputStream(
				s.getOutputStream());
		//获取通道内的流 输出流 OutputStream
		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();
	}
}
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 UploadServer {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		
		//创建服务器端Socket()对象
		ServerSocket ss = new ServerSocket(6666);
		//监听客户端
		Socket s = ss.accept();
		//创建通道流
		BufferedInputStream bis = new BufferedInputStream(
				s.getInputStream());
		//输出图片文件
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("copy.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());
		
		//释放资源
		s.close();
		bos.close();
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章