[Java]一个TCP文本上传相关的异常处理和偶然引出的中文编码问题

源程序:

Client:

class  TcpClient4
{
	public static void main(String[] args) 
	{
		Socket s=null;//要在块外定义,不然catch中无法找到!------->并初始化,否则finally中判断时提示你可能尚未初始化!!
		try
		{
			s=new Socket("127.0.0.1",10013);//单独try,连不上直接终止运行,没有继续运行下面程序的必要!

			try
			{
				//经测试,按记事本默认编码保存,这里只有用UTF-8解码复制结果是乱码!按utf-8保存,复制结果仍然不一致(字节数都不一致!),但竟然不乱码!(开头多了个?)
				//这里的测试:其中sscc.txt是utf-8文件,文本:“你妈逼你结婚了吗?”30个字节。故意用gb2312解码,结果当然乱码:字节、内容都不一致,但这里按utf-8正常解码,下面一切默认,则不乱码,前边多了个?,并且字节数不一致,显示是21个字节,说明是GBK或GB2312编码!
				BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("c:\\sscc.txt"),"utf8"));//底层都是读字节,这里可以指定码表,并且是用转换流转成字符流读取方式

				//BufferedReader bufr=new BufferedReader(new FileReader("c:\\x.txt"));

				//这是默认编码GBK
				PrintWriter pw=new PrintWriter(s.getOutputStream(),true);//第二个参数true:自动刷新

				String line=null;

				while((line=bufr.readLine())!=null){
					pw.println(line);//自动加回车换行,那边readLine可以判断并成功读取一行
				}
			}
			catch (Exception ex)
			{
				throw new RuntimeException(ex);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}

		finally{
			try
			{
				//s是引用
				if(s!=null)
					s.close();
			}
			catch (Exception exc)
			{
				throw new RuntimeException(exc);
			}
		}
	}
}

Server:

class  TcpServer4
{
	public static void main(String[] args) 
	{
		ServerSocket ss=null;//要在块外定义,不然catch找不到!
		Socket s=null;
		try
		{
			ss=new ServerSocket(10013);

			s=ss.accept();

			try
			{
				BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));

				PrintWriter pw=new PrintWriter(new FileWriter("c:\\x2.txt"),true);

				String line=null;

				while((line=bufr.readLine())!=null){
					pw.println(line);
				}
			}
			catch (Exception ex)
			{
				throw new RuntimeException(ex);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
		finally{
			try
			{
				if(s!=null)
					s.close();

				if(ss!=null)
					ss.close();
			}
			catch (Exception exc)
			{
				throw new RuntimeException(exc);
			}
			
		}
		
	}
}
关于异常处理:

1.Socket相关要单独try处理,连接出现问题就没有继续运行下面代码的必要;

2.Socket(引用)要在try块外定义,不然catch块找不到!

3.Socket需要在定义时初始化,不然编译提示:finally中的if判断可能会出现Socket尚未初始化的情况!


按不同码表复制的结果:

经测试验证:按照记事本默认ANSI编码保存,程序中一切按照默认码表处理,正常复制,结果的内容和字节数均与源文件一致,没有问题:ANSI对应中文编码为GBK,而FileReader,FileWriter等的默认码表也是GBK,不乱码

按照UTF-8保存文本(可以从字节数看出来,UTF-8中文一个汉字3个字节),客户端读取时按照UTF-8正常解码(解码出汉字字符串),其他地方一切按默认编码,结果并不乱码,只是文本开头莫名多了一个?

结论:有些原因不明,只能看实际结果,不要主观臆测,想当然!实际编程中只要严格按照同一种码表编码和解码就不会出现问题!抓住这一点,其他一切不要深究,不要冒险尝试!!!


上传成功后反馈信息的程序改进:

注意在客户端的while循环结束后(它是可以结束的,读文件),如果没有额外再输出一个结束标记,那么由于其下面还有一个阻塞式的readLine等待反馈信息,而服务端那边的while得不到结束标记,则两端都会陷入阻塞。

Client:

class  TcpClient4
{
	public static void main(String[] args) 
	{
		Socket s=null;//要在块外定义,不然catch中无法找到!------->并初始化,否则finally中判断时提示你可能尚未初始化!!
		try
		{
			s=new Socket("127.0.0.1",10013);//单独try,连不上直接终止运行,没有继续运行下面程序的必要!

			try
			{
				
				BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("c:\\xxcc.txt"),"gbk"));

				//BufferedReader bufr=new BufferedReader(new FileReader("c:\\x.txt"));

			
				PrintWriter pw=new PrintWriter(s.getOutputStream(),true);//第二个参数true:自动刷新

				String line=null;

				while((line=bufr.readLine())!=null){
					pw.println(line);//自动加回车换行,那边readLine可以判断并成功读取一行
				}

				//可以定义结束标记那边判断(读取,传过去,那边得到后判断,用DataOutputStream),比如空行(Tomcat的做法,分割请求和响应的头和主体)和时间戳(长整型,DataInputStream的readLong方法),这里调用Socket的方法关闭输出流
				s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记-1,让那边的循环停下来

				//读取一个上传成功的反馈
				BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));

				String str=bufIn.readLine();//一样需要换行符

				System.out.println(str);

				bufr.close();

				s.close();//和Socket相关的流随Socket关闭而自然关闭
			}
			catch (Exception ex)
			{
				throw new RuntimeException(ex);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}

		finally{
			try
			{
				//s是引用
				if(s!=null)
					s.close();
			}
			catch (Exception exc)
			{
				throw new RuntimeException(exc);
			}
		}
	}
}

Server:

class  TcpServer4
{
	public static void main(String[] args) 
	{
		ServerSocket ss=null;//要在块外定义,不然catch找不到!
		Socket s=null;
		try
		{
			ss=new ServerSocket(10013);

			s=ss.accept();

			try
			{
				BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));

				PrintWriter pw=new PrintWriter(new FileWriter("c:\\x2.txt"),true);

				String line=null;

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

				//那边关闭Socket输出流以结束这边的循环,那么这里仍然可以调用,难道是重新打开?
				PrintWriter pout=new PrintWriter(s.getOutputStream(),true);

				pout.println("Upload Succeed.");//必须有回车换行,那边才能readLine

				pw.close();//和Socket有关的流随Socket关闭而自然关闭!
				
			}
			catch (Exception ex)
			{
				throw new RuntimeException(ex);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
		finally{
			try
			{
				if(s!=null)
					s.close();

				if(ss!=null)
					ss.close();
			}
			catch (Exception exc)
			{
				throw new RuntimeException(exc);
			}
			
		}
		
	}
}

文件成功复制,测试成功。客户端结果:

D:\java\practice3>java TcpClient4
Upload Succeed.

D:\java\practice3>

你可能感兴趣的:([Java]一个TCP文本上传相关的异常处理和偶然引出的中文编码问题)