day22网络编程 UDP、TCP协议

一.网络编程的三要素:
1)找到IP地址
2)必须有端口
3)必须有协议(TCP协议,UDP协议)


举例:
我想和高圆圆说话...
1)我首先要找到她...需要知道的位置(IP)
2)找到了她之后,怎么跟她说话?对着她的耳朵说话....
3)找到她了,对着她的说:
i love you ....
高圆圆听不懂英语...(协议)
中文:我爱你



1.IP地址:
PC机器都有唯一的标识:ip

ip地址:192.168.1.100  已经优化的ip

ip每一个段落转成二进制:
11000000 10101000 00000001  01100100
192 168 1 100

ip如果每次写成二进制数据,非常麻烦,所以采用点分十进制法,将每一个二进制数据转成十进制数据,中间用.隔开

常见的IP:
A类:1.0.0.1---127.255.255.254:第一个号段为网络号段,后三个号段为主机号段
256^3=16777216台计算机  (强大的部门),通常:国防部(美国的五角大楼)
B类:128.0.0.1---191.255.255.254:前两个号段为网络号段,后两个号段为主机号段()
256^2: 通常大学里面或者一些地方政府部门
C类:192.0.0.1---223.255.255.254:前三个好号段为网络号段,后一个号段为主机号段
192.168.1.100(私人地址:家庭或者单位)

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机器的网络通信  
原理和声呐系统是一样的

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


计算机中每一个软件都它有自己的的端口号:通过360查看每个软件的对应应用程序的端口号

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

3.协议:
TCP协议和UDP协议 区别:

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

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




thunder://
http://
ftp://
file://
mail:

二.网络编程

1. InetAddress类

   该类没有构造方法,表示互联网协议 (IP) 地址。
  如果一个类中没有构造方法:
  A:这个类里面的成员方法都是静态(Math,Arrays,Collections)
  B:单例模式(设计模式):在内存始终只有一个对象
  将构造方法私有化
  在成员变量创建该类的实例(并且这个实例私有化被static修身)
  提供该类公共方法可以通过外界调用
  C:该类中会某些 静态成员方法的返回值是该类本身(InetAddress就是一个例子)
  
  public class Demo{
  private Demo(){
  
  }
  
  public static Demo get(){
  return new Demo() ;
  }
  }
,,,,

例子:

public class InetAddressDemo {
	
	public static void main(String[] args) throws UnknownHostException {
		
		//public static InetAddress getByName(String host)throws UnknownHostException在给定主机名的情况下确定主机的 IP 地址
		//该主机名可以是计算机名(PC机器的计算机名称),也可以是ip地址的文本表现形式,通过这个方法返回的是ip地址对象
//		InetAddress address = InetAddress.getByName("USER-20171205ZR") ;
		
		InetAddress address = InetAddress.getByName("192.168.10.101") ;
		
//		System.out.println(address);//USER-20171205ZR/192.168.10.101
		
		//如何通过得到的addressIp地址对象来得到当前计算机名称
		//public String getHostName()获取此 IP 地址的主机名。 
		//如果此 InetAddress 是用主机名创建的,则记忆并返回主机名
		
		String name = address.getHostName() ;
		System.out.println("name:"+name);
		
		//获取具体的ip地址文本形式
		//public String getHostAddress()返回 IP 地址字符串(以文本表现形式)。 
		String ip = address.getHostAddress() ;
		System.out.println("ip:"+ip);//192.168.10.101
 	}
}

2.UDP协议

UDP协议(发送端和接收端),不需要建立连接通道
 
  发送端
  步骤:
   1)创建UDP协议发送端的Socket对象
   2)创建数据报包:通过这个数据包将数据发送到接收端
   3)调用UDP协议发送端发送的方法
   4)关闭资源

例子:

public class SendDemo {
	
	public static void main(String[] args) throws  Exception {
		//使用UDP协议创建Socket对象不是Socket类对象,(客户端的套接字)
		//DatagramSocket:用来发送和接收数据报包的套接字。
		//public DatagramSocket() throws SocketException
		DatagramSocket ds = new DatagramSocket() ;//创建了UDP协议的Socket对象
		
		
		//发送一句话
		String str = "hello,udp,i'm coming" ;
		
		//2)创建数据报包对象
//		public DatagramPacket(byte[] buf, int length ,InetAddress address,int port)
		//将字符串数据转换成字节数组
		byte[] bys = str.getBytes() ;
		//当前字节数组的实际长度
		int len = bys.length ;
		
		//创建InetAddress对象,Ip地址对象
		InetAddress address = InetAddress.getByName("192.168.10.101") ;
		
		//指定端口号:0-65535是有效端口号
		int port = 10086 ;
		
		DatagramPacket dp = new DatagramPacket(bys, len, address, port) ;
		
		//3)调用UDP协议DataScoket类里面发送的方法
		//public void send(DatagramPacket p) throws IOException从此套接字发送数据报包
		ds.send(dp) ;
		
		//4)关闭资源
		ds.close() ;
	}
}

UDP协议的接收端
  
  1)创建接收端的Socket对象
  2)创建一个数据报包接收发送端发送来的数据报包(接收容器)
  3)接收数据,调用DataScoket类中的接收的方法来接收数据包
  4)解析数据报包里面的实际数据,显示在控制台上
  5)关闭资源
  
  
  多次运行接收端,会出现一处:BindException:绑定异常:
   接收端运行一次就可以了,端口号已经被占用了,不能再继续使用这个端口号

例子:

public class ReceiveDemo {
	
	public static void main(String[] args) throws IOException {
		
		//public DatagramSocket(int port)
		//1)创建UDP协议接收端的scoket对象
		DatagramSocket ds = new DatagramSocket(10086) ;
		
		//2)创建数据报包:DatagramPacket,来接收发送端发送来的数据
		//public DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长度为 length 的数据包。
		//定义字节数组:缓存区
		byte[] bys = new byte[1024] ;
		DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
		
		//3)调用DataScoket里面接收的方法
//		public void receive(DatagramPacket p) throws IOException从此套接字接收数据报包
		ds.receive(dp) ;// 阻塞式方法(等待发送端发送数据,只要没有数据,就一直等待,有数据的话将数据显示控制)
		
		//4)4)解析数据报包里面的实际数据,显示在控制台上
		//获取到ip字符串表现形式
		//public InetAddress getAddress():首先通过数据报包得到一个Ip地址对象:InetAddress
		InetAddress address = dp.getAddress() ;
		//可以通过getHostAddress()得到ip地址的文本形式
		String ip = address.getHostAddress() ;
		
		//解析发送端发送来的实际数据
//		 byte[] getData() 返回数据缓冲区。 
//			int getLength() 返回将要发送或接收到的数据的长度。 
			
			byte[] dataBys = dp.getData() ;
			//获取数据缓存区中的实际长度
			int len = dp.getLength() ;
			
			//将字符串显示出来
			String str = new String(dataBys,0,len) ;
			
			//输出到控制台
			System.out.println(ip+":给你发送了:"+str);
		
		
	}
}


发送端的数据来源不是简单的一条语句而是不停的键盘录入
 
   键盘录入的方式:
   1)Scanner类
   2)BufferedReader类(字符缓冲流)特有功能:readLine():一次读取一行    (System.in)
  
  快船,QQ
  
 
  需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)
   (使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中)

 接收端不停的接收键盘录入的数据显示到控制台上


public class ReceiveTest {
	
	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) ;
			
			//获取ip字符串的表现形式
			String ip = dp.getAddress().getHostAddress() ;
			
			//解析数据接收容器,获取里面实际的内容
			byte[] buff = dp.getData();
			int len = dp.getLength() ;//获取实际数据缓冲区实际长度
			String s = new String(buff, 0, len) ;
			
			//显示到控制台
			System.out.println("from" + ip +"data is :"+s);
			
//			//释放资源,为了模仿一直有发送端发送来的数据,所以无需关闭接收端Socket
//			ds.close() ;
		}
		
		
	}
	
}

public class SendTest {

	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("886".equals(line)){
				break ;
			}
			//创建数据报包
			//DatagramPacket(byte[] bys,int length,InetAddrss address,int port)
			byte[] bys = line.getBytes() ;
			DatagramPacket dp = new DatagramPacket(bys, bys.length,
					InetAddress.getByName("192.168.10.101"), 12345);
			
			//发送数据
			ds.send(dp) ;
		}
		
		//释放资源
		ds.close() ;
	}
}



需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)
  (使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中)


public class ChatRoom {

	public static void main(String[] args) {
		
		try {
			//发送端和接收端分别自定义类表示发送端线程和接收端线程
			//SendThread,receiveThread
			//需要有两个Socket对象
			
			//创建发送端和接收端的Socket对象
			DatagramSocket sendSocket = new DatagramSocket() ;
			DatagramSocket receiveSocket = new DatagramSocket(8888) ;
			
			//创建资源对象
			SendThread st = new SendThread(sendSocket) ;
			ReceiveThread rt = new ReceiveThread(receiveSocket) ;
			
			//创建线程类对象
			Thread t1 = new Thread(st) ;
			Thread t2 = new Thread(rt) ;
			
			//启动线程
			t1.start() ;
			t2.start() ;
			
			
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
}

public class SendThread implements Runnable {
	//定义一个变量
	private DatagramSocket ds ;
	public SendThread(DatagramSocket ds){
		this.ds = ds ;
	}
	
	@Override
	public void run() {
		try {
			//创建发送端Socket对象
			//以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("192.168.10.101"), 8888) ;
				
				//发送数据
				ds.send(dp) ;
				
			}
			//释放资源
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//释放资源
			if(ds!=null){
				ds.close() ;
			}
		}
		
	}

}

public class ReceiveThread implements Runnable {
	
	private DatagramSocket ds ;
	public ReceiveThread(DatagramSocket ds){
		this.ds =ds ;
	}
	
	@Override
	public void run() {
		//创建接收端的socket对象		
		try {
			while(true){
				
				byte[] bys = new byte[1024] ;
				DatagramPacket dp = new DatagramPacket(bys, bys.length) ;

				//接收数据
				ds.receive(dp) ;
				
				//获取ip字符串的表现形式
				String ip = dp.getAddress().getHostAddress() ;
				
				//解析数据接收容器,获取里面实际的内容
				byte[] buff = dp.getData();
				int len = dp.getLength() ;//获取实际数据缓冲区实际长度
				String s = new String(buff, 0, len) ;
				
				//显示到控制台
				System.out.println("from" + ip +"data is :"+s);
			}
			
			//接收要不停接收数据,不需要关闭
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

3.TCP协议

使用Socket编程里面的TCP协议
  客户端和服务器端的交互
  客户端步骤:
   1)创建客户端的socket对象 (客户端套接字流的形式)
   2)获取通道的内流(输出流)
   3)使用输出流对象写数据
   4)关闭客户端的Socket对象
  
  对于TCP协议来说:客户端和服务器端是需要建立连接通道的,如果没有启动服务器端,先启动客户端:
   报异常:java.net.ConnectException
     Connection refused: connect :连接被拒绝!

public class ClientDemo {
	
	public static void main(String[] args) throws  IOException {
		
		//1)1)创建客户端的socket对象:此类实现客户端套接字
		//构造方法:Socket类
		//public Socket(InetAddress address, int port)
		//throws IOException创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 
//		Socket s  = new Socket(InetAddress.getByName("192.168.10.101"), 10010) ;
		//public Socket(String host, int port)
		//host:可以是主机名称也可是ip地址的字符串表现形式
		Socket s = new Socket("192.168.10.101", 10010) ;
		
		//2)	获取通道的内流(输出流)
		//public OutputStream getOutputStream()
        	//throws IOException返回此套接字的输出流。
		OutputStream out = s.getOutputStream() ;
		
		//3)客户端通道内的流给服务器写数据
		out.write("hello,TCP,我来了...".getBytes()) ;
		
		//4)关闭客户端socket
		s.close() ;
	}
}

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

public class ServerDemo {

	public static void main(String[] args) throws IOException {
		
		//1)ServerSocket此类实现服务器套接字。服务器套接字等待请求通过网络传入
		//public ServerSocket(int port) 构造方法:创建绑定到特定端口的服务器套接字
		ServerSocket ss = new ServerSocket(10010) ;
		System.out.println("等待客户端连接...");
		//2)监听客户端的连接:请求等待介入
		//public Socket accept()
	     //         throws IOException侦听并接受到此套接字的连接
		//该方法特点:服务器在连接到客户端之前,此方法一直处于阻塞
		Socket s = ss.accept() ;//一旦客户端那边也是端口,阻塞式方法就会结束
		System.out.println("客户端已经连接...");
		//3)获取通道内的输入流对象
		//public InputStream getInputStream()
		InputStream in = s.getInputStream() ;
		
		//4)将客户端发送的数据显示到控制台上
		//定义一个缓冲数组
		byte[] bys = new byte[1024] ;
		int len = in.read(bys) ;//获取到实际的字节数  (阻塞式)
		String str = new String(bys, 0, len) ;
		
		//获取IP地址的文本形式
//		public InetAddress getInetAddress()返回套接字连接的地址。 
		InetAddress address = s.getInetAddress() ;
		//在通过ip地址对象getHostName();
		String ip = address.getHostAddress() ;
		
		//输出显示到控制台
		System.out.println(ip+"传递的数据是:"+str);
		
		//关闭服务器端socket
		s.close() ;
		
	}
}



客户端发送数据,服务器端给客户端反馈数据...

public class ClientDemo {
	
	public static void main(String[] args) throws IOException {
		
		//创建客户端的Socket对象
		Socket s = new Socket("192.168.10.101", 6666) ;
		
		//获取通道内的输出流
		OutputStream out = s.getOutputStream() ;
		
		//将该数据发送到服务器端(通过通道内的流)
		out.write("今天天气很好,没有雾霾".getBytes()) ;
		
		
		//获取到服务器端反馈过来的数据
		//获取通道内内的输入流对象
		InputStream in = s.getInputStream() ;
		//读数据
		byte[] bys = new byte[1024] ;
		int len = in.read(bys) ;//读取服务器端发送来的实际字节数(阻塞式)
		//显示服务器端反馈的数据
		String client = new String(bys, 0, len) ;
		System.out.println("clinet:"+client);
		
		
		
		//释放资源
		s.close() ;
	}
}

public class ServerDemo {

	public static void main(String[] args) throws IOException {
		
		//1)创建服务器端Socket对象
		ServerSocket ss = new ServerSocket(6666) ;
		System.out.println("正在等待客户端连接...");
		
		//2)监听客户端的连接
		Socket s = ss.accept() ;//阻塞式方法结束,连接了(侦听到客户端的和的服务器端端口一致)
		System.out.println("客户端已连接...");
		
		//3)服务器端获取通道内输入流对象
		InputStream in = s.getInputStream() ;
		//客户端发送端数据显示控制台
		byte[] bys = new byte[1024] ;
		int len = in.read(bys) ;//阻塞式
		String server = new String(bys, 0, len) ;
		
		//输出客户端给服务器端发送的数据
		System.out.println("server:"+server);
		
		//服务器反馈
		//获取通道内的输出流
		OutputStream out = s.getOutputStream() ;
		//给客户端反馈数据
		out.write("我已收到,谢谢".getBytes()) ;
		
		//关闭资源
		s.close() ;//关闭掉侦听的客户端所在的通道内的对象(Socket)
//		ss.close() ;
		
	}
}



需求:客户端键盘录入数据,服务器端将数据显示控制台


public class ClientDemo {
	
	public static void main(String[] args) throws  IOException {
		
		//1)创建客户端socket对象
		Socket s  = new Socket("192.168.10.101", 2222) ;
		
		//2)数据是键盘录入(IO流的形式)
		//BufferedReader字符流封装数据,读取键盘录入的数据
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
		
		//3)客户端要发送数据,获取通道内的流,getOutputStream() :字节输出流
		//使用字符缓冲输出流封装通道内的流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
				s.getOutputStream()));
		//利用BufferedReader一次读取一行数据:readLine
		//BuffereWriter将键盘录入的数据(写到通道内的流中)以流的形式发送端服务器端:  newLine() ,flush()
		String line = null ; 
		while((line=br.readLine())!=null){
			//键盘录入一行数据,就把一行数据写入到被封装的通道内的流中
			
			//什么时候结束
			//自定义结束条件
			if("over".equals(line)){
				break ;
			}
			
			bw.write(line) ;
			bw.newLine() ;
			bw.flush() ;
		}
		
		//关闭资源
		s.close() ;
	}
}

服务器端将客户端键盘录入的数据读取出来显示控制台

public class ServerDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建服务器端的Socket对象
		ServerSocket ss = new ServerSocket(2222) ;
		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);
		}
		
		//关闭资源
		//ss.close() ;//服务器端 不需要关闭
		s.close() ;
//		br.close() ;
	}
}



客户端键盘录入,服务器输出将录入的内容输出到文本文件

public class ClientDemo {
	
	public static void main(String[] args) throws IOException {
		
		//创建客户端的Socket对象
		Socket s = new Socket("192.168.10.101", 3456) ;
		
		//键盘录入: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() ;
	}
}

public class ServerDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建服务器端的Socket对象
		ServerSocket ss = new ServerSocket(3456) ;
		
		//2)监听客户端连接
		Socket s = ss.accept() ;
		
		//3)封装通道内的流
		BufferedReader br = new BufferedReader(new InputStreamReader(
				s.getInputStream()));
		
		//4)服务器端输出一个文本文件
		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() ;
	}
}





需求:客户端一个文本文件,服务器端将客户端文本文件中的内容展示到控制台上

public class ClientDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建客户端的Socket对象
		Socket s = new Socket("192.168.10.101", 4567) ;
		
		//2)要封装文本文件:
		BufferedReader br = new BufferedReader(new FileReader(
				"InetAddressDemo.java"));
		
		//3)封装通道内的流:将字节输出流封装成字符缓冲输出流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
				s.getOutputStream()));
		
		//4)需要将文本文件中的数据(内容)写入到被封装的通道内的流中
		String line = null ;
		while((line=br.readLine())!=null){
			//读取一行,将数据写一行到通道流中
			bw.write(line) ;
			bw.newLine() ;
			bw.flush() ;
		}
		
		//释放资源
		br.close() ;
		s.close() ;
	}
}

public class ServerDemo {

	public static void main(String[] args) throws IOException {
		
		//创建服务器端是Socket对象
		ServerSocket ss = new ServerSocket(4567) ;
		
		//监听客户端
		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() ;
	}
}



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

public class UploadClient {
public static void main(String[] args) throws  IOException {
		
		//1)创建客户端的Socket对象
		Socket s = new Socket("192.168.10.101", 6666) ;
		
		//2)封装文本文件,对于文本文件字符缓冲输入流
		BufferedReader br = new BufferedReader(
				new FileReader("SellTicket.java"));
		
		//3)封装通道内字节输出流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
				s.getOutputStream()));
		
		//将SellTicket.java文件中的内容一次读取一行写入到通道内的流中
		String line = null ;
		while((line=br.readLine())!=null){  //阻塞
//			
			bw.write(line) ;
			bw.newLine() ;
			bw.flush() ;
		}
		
		//方式1
		//定义一个结束标记
//		bw.write("over") ;
//		bw.newLine() ;
//		bw.flush() ;
		
		//通过这个方法告诉服务器端,客户端这边没数据了,读完了,你反馈
		s.shutdownOutput() ;//(推荐使用这种方式)
		
		//读取服务器端的反馈
		//获取通道内的输入流对象
		BufferedReader brClinet = new BufferedReader(new InputStreamReader(
				s.getInputStream()));
		//读数据
		String fk = brClinet.readLine() ;
		System.out.println(fk);
		
		
		
		//释放资源
		br.close() ;
		s.close() ;
	}
}

public class UploadServer {
	
	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("copy.java")) ;
		
		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() ;
		
		//关闭资源
		bw.close() ;
		s.close() ;
		
	}
}




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

public class UploadClient {
	
	public static void main(String[] args) throws  IOException {
		
		//创建客户端的socket对象
		Socket s = new Socket("192.168.10.101", 8888) ;
		
		//先封装文件
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("林青霞.jpg")) ;
		
		//获取通道内的流 输出流 OutputStream
		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() ;
	}
}

public class UploadServer {
	
	public static void main(String[] args) throws IOException {
		
		//服务器端
		//获取socket对象
		ServerSocket ss = new ServerSocket(8888) ;
		
		//监听
		Socket s = ss.accept() ;
		
		//封装通道内的流
		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 out = s.getOutputStream() ;
		out.write("文件上传成功".getBytes()) ;
		
		
		//释放资源
		bos.close() ;
		s.close() ;
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值