欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

程序需求:客户端读取当前项目下的该图片文件,服务器端将文件的内容复制,输出一个新的图片文件:mm.jpg (服务器加上反馈)

程序员文章站 2022-04-18 11:46:44
...

TCP编程;(建立连接通道)

客户端的开发步骤:

    1) 创建客户端的Socket对象

        Socket s  = new Socket(“ip”,端口) ;

                      Socket:就是客户端的Socket
          构造方法
  public Socket(InetAddress address, int port)
  public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式。

    2) 获取该通道内的输出流对象

        OutputStream out = s.getOutputStream();

            -封装通道内的流:BufferedWriter

     3) 写数据

           out.write(“…”.getBytes()) ;

    4) 释放资源

        s.close() ;

客户端程序:

public static void main(String[] args) throws  IOException {
		
		//创建Socket对象 Socket("IP地址", 自定义端口号0~65535,其中0~1024不可用);
		Socket s = new Socket("192.168.10.1", 19191);
		
		//封装图片文件(因为传输文件,所以这里使用字节流传输故用BufferedInputStream)
		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);
			
			//public void flush()
	         //  throws IOException刷新此输出流并强制写出所有缓冲的输出字节
			bos.flush();
		}
		//通知对方,数据已经完了
		s.shutdownOutput();
		
		//获取服务器端的反馈数据
		//获取通道内的输入流对象
		InputStream is = s.getInputStream() ;
		byte[] buffer = new byte[1024] ;
		int len2 = is.read(buffer) ;
		String data = new String(buffer, 0, len2) ;
		System.out.println(data);
		
		//释放资源
		s.close();
		bis.close();
		
	}
}

服务器端的开发步骤:

    1) 创建服务器端的Socket对象,并且绑定某个端口号

        ServerSocket ss = new ServerSocket(端口号) ;

    2) 监听(阻塞式方法)

        Socket s = ss.accept() ;

    3) 获取通道内输入流对象

        InputStream = s.getInputStream() ;

            ---àBufferedReader流对象

4) 一次读取一个字节数组的方式,输出数据(IO流读的操作)


服务器端程序:

public static void main(String[] args) throws IOException {
		
		//创建Socket对象(在服务器端用ServerSocket(跟客户端一致的端口号))
		ServerSocket ss = new ServerSocket(19191);
	//监听客户端的连接(阻塞方法)public Socket accept():throws IOException侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞
		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();
		
	}

问题一:

        程序运行抛出异常ava.net.BindException: Address already in use: JVM_Bind 

 异常原因:

        地址被绑定,因为已经有服务器在监听客户端连接

问题二:

        程序运行抛出异常java.net.ConnectException: Connection refused: connect 连接被拒绝

 异常原因:

        不要先运行客户端,客户端的连接需要服务器监听到才能连接,故得先运行服务器端程序,再运行客户端。

问题三:

        客户端文本文件(使用字符缓冲流),服务器端复制该内容,并且输出一个新的文本文件,并且服务器给出反馈

              使用缓冲流的时候,针对文本文件操作,客户端和服务器端通道内的流来说它不能用null作为信息的结束条件..

解决方案:

       1) 客户端自定义结束条件,(往通道内输出流写一些结束条件),服务器端如果读到了该内容,就表示客户端的文本文件已经上传完毕,服务器端就开始反馈!(存在问题:如果文本文件中存在与结束条件相同的语句,那么文本未读完就会结束数据传输,因此尽量不要用自定义)
if("886".equals(line)) {   
 //自定义结束条件

break ;
}

    2) 直接在客户端的Socket对象中,通知服务器端反馈,并且客户端的文本文件已经读完客户端的数据,用public void shutdownOutput():通知服务器端(我没有数据了,你赶紧反馈)

        语句形式为:Socket对象.shutdownOutput();此语句可通知对方数据已读完。


相关标签: Java程序