异常和TCP通讯

第七章 异常处理

* 异常处理机制中的try-catch
* 语法:
* try{
* 代码片段
* }catch(XXXException e){
* 当try中的代码片段出现了XXXException后的处理代码
* }

* try中的代码片段报错行以下的代码都不会运行
* 应当有一个好习惯,在最后一个catch处捕获Exception
* 这样能避免因为一个未捕获的异常导致程序中断

* finally
* finally块是异常处理机制的最后一块,只能跟在最后一个catch之后或直接跟在try之后
* finally可以保证只要程序执行到try代码块中,无论try中的代码是否出抛出异常,finally中的代码都会执行
* 所以通常会将无关乎异常,必定要执行的代码放在finally中
*
* 例如:IO中的关闭流操作,就适合放在finally中

* JDK7之后推出了一个特性,自动关闭
* 可以将流这种需要最后调用close方法释放资源的操作从繁琐的try-catch-finally中简化
* 语法:
* try(创建最终需要关闭的对象){
* 正常代码块
* }catch(XXXException e){
* 异常处理代码
* }

* 凡是实现了AutoCloseable接口都可以被自动关闭
* 所有的流以及RandomAccessFile都实现了该接口
* 自动关闭是编译器认可,最终编译后的class文件中会被改为在finally中关闭
* 样子参考FinallyDemo2

throw 异常的抛出
* 当符合语法却不符合业务逻辑时,需要主动抛出异常

1 public void setAge(int age) throws IllegalAgeException {
2 if(age>0&&age<100) {
3 this.age = age;
4 }else {
5 throw new IllegalAgeException("年龄不合法");
6 }
7 }

* 当一个方法中使用throw抛出一个异常时,就要在当前方法上使用throws声明该异常的抛出
* 以便于通知调用方法者在调用方法时要处理异常
* 只有RuntimeException及其子类在抛出时编译器不要求必须写throws声明
* 其他异常则必须声明,否则编译不通过

* 当调用一个含有throws声明异常抛出的方法时编译器会提示必须处理该异常
* 处理的方式有两种:
* 1:使用try-catch捕获并处理异常
* 2:在当前方法上继续使用throws声明将该异常抛出

throws的重写规则:
* 子类在重写父类含有throws声明异常抛出的方法时:
* 1,重写父类方法可以原样抛出异常
* 2,重写父类方法可以什么都不抛
* 3,重写父类方法可以抛出父类的部分异常
* 4,重写父类方法可以抛出父类抛出异常的子类型异常
*
*不允许抛出额外异常(即抛出的异常与父类异常之间没有(继承)关系)
*不允许抛出父类抛出异常的父类型异常

自定义异常
*通常是用来说明业务逻辑错误,一定要把异常名称(类名)写明白
* 继承Exception||其他异常,以便编译器识别
* 重写父类构造方法
【案例】

public class IllegalAgeException extends Exception{
private static final long serialVersionUID = 1L;

public IllegalAgeException() {
super();
}
public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public IllegalAgeException(String message, Throwable cause) {
super(message, cause);
}
public IllegalAgeException(String message) {
super(message);
}
public IllegalAgeException(Throwable cause) {
super(cause);
}
}

java异常API

RuntimeException
java异常可以分为可检测异常,非检测异常
可检测异常:对于声明抛出异常的任何方法,java编译器都会验证并强制执行声明规则或处理规则,不捕捉这个异常编译器就通不过(报红线)

非检测异常:不遵循处理规则或声明规则,产生异常时,编译器不会检查是否已经解决类这样一个异常。
RuntimeException类属于非检测异常,常见的有:
IllgalArgumentException:传递了一个不合法或不正确的参数
NullPointerException:空指针异常
ArrayIndexOutOfBoundsException:数组下标越界异常
ClassCastException:类强制转换异常
NumberFormatException:数字格式异常

void printStackTrace()
Throwable中定义的一个方法:输出错误信息,跟踪异常发生时执行堆栈的内容

第八章 TCP通讯

TCP 可靠性传输协议(java开发服务端常用)
UDP 不可靠传输协议
【聊天室项目】
一、客户端:
1,声明Socket变量socket;
2,创建构造方法,在构造方法中初始化socket,设置两个参数:1,服务端IP地址,2,访问端口;
(实例化的过程就是向服务端发起访问申请的过程,若服务端没有响应,实例化会抛出异常)
二、服务端:
1,声明ServerSocket变量server
2,创建构造方法,在构造方法中初始化server,server初始化时会向系统传递并申请端口号,若端口号已被占用,程序会抛出端口被占用的异常,这时我们需要更换端口号
3,在main方法中new一个实例对象,用对象调start方法
4,在start方法中,声明一个socket用于接收server.acccpt()方法监听服务端口的结果返回值;一旦有一个客户端通过该端口建立了连接,该方法会返回一个socket实例,通过该socket实际即可与该客户端建立连接;

三、客户端
1,在main中new一个实例对象,调用start方法
2,在start方法中,创建输出流,用于向服务端传递消息(可循环传递)
3,在start方法中,创建输入流,用于接收服务端传送过来的消息

四、服务端
1,在start方法中,创建输入流,用于接收客户端传递的消息(可循环接收)
2,在start方法中,创建输出流,用于回复客户端的消息(原样返回)(可循环发送)
3,这两个循环和main方法中循环监听端口并根据客户端连接抛出socket实例的两种循环会出现冲突,所以需要设计一条新线程,使之并发处理每一个客户连接后的通讯socket输入输出循环,在start方法中调用线程

五、客户端
1,循环读取服务端发回的消息时,会因为输入消息的IO阻塞,读取不及时,需要设计并发线程异步执行,创建内部类并实现runnable,重写run方法
2,将上一步创建的输入流语句剪切至run方法中,循环接收服务端发送过来的消息
3,在start方法中,实例化ServerHandler ,启动线程并调用

六、服务端
1,将原样返回给客户端的消息传递给所有客户端(即让所有客户端都可以看到其他客户端发送的消息,达到相互通讯的目的),根据内部类可以访问外部类成员变量的规则,我们在外部类创建成员数组变量allOut[]arr,将要发送给客户端的输出流存放在该数组中,遍历每一个元素.println(),则所有客户端都可接收到该输出流文件
2,处理当一个客户端断开连接后的情况(因为是必走的步骤,所以放在finally{}中执行):
2.1)将断开的客户端的pw从数组中删除
思路1:遍历数组,查询数组元素与断开的pw是否==,若true,将数组最后一个元素赋值到断开的pw处,再将最后一个元素缩容掉
思路2:遍历数组,查询数组元素与断开的pw是否!=,若true,则表明该元素未断开,将未断开的元素添加到另外的空数组中,最后将包含所有的未断开的数组复制到原数组
2.2)关闭socket释放资源:socket.close();
3,因为有多个线程可能同时操作allOut数组,如遍历输出,扩容,缩容等,这样就导致了线程之间不安全,所以要考虑用synchronized()来解决这个问题。互斥锁;

  1 package socket;
  2
  3 import java.io.BufferedReader;
  4 import java.io.BufferedWriter;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 import java.io.InputStreamReader;
  8 import java.io.OutputStream;
  9 import java.io.OutputStreamWriter;
 10 import java.io.PrintWriter;
 11 import java.net.Socket;
 12 import java.net.UnknownHostException;
 13 import java.util.Scanner;
 14 /**
 15 * 聊天室客户端
 16 * @author soft01
 17 */
 18 public class Client {
 19 /*
 20 * java.net.Socket
 21 * Socket翻译为套接字
 22 * 封装了TCP通讯协议的细节,使我们可以通过两条流与远端进行双向数据传输,达到通讯的目的
 23 */
 24 private Socket socket;
 25 Scanner scan = new Scanner(System.in);
 26 /**
 27 * 客户端的构造方法
 28 */
 29 public Client() {
 30 try {
 31 /*
 32 * 实例化 Socker时通常需要传入两个参数
 33 * 参数1:服务端的IP地址
 34 * 参数2:服务端的端口号
 35 * 通过IP地址可以找到服务端计算机
 36 * 通过端口可以找到运行在服务端计算机上的服务端应用程序
 37 * 在这里实例化Scoket的过程就是连接服务端的过程
 38 * 若服务端没有响应,则这里实例化会抛出异常
 39 */
 40 System.out.println("正在连接服务端……");
 41 socket=new Socket("178.10.1.94",8088);//第一个参数是服务端网址,第二个参数是服务端的端口
 42 System.out.println("与服务端建立连接!");
 43 } catch (UnknownHostException e) {
 44 e.printStackTrace();
 45 } catch (IOException e) {
 46 e.printStackTrace();
 47 }
 48 }
 49 /**
 50 * 客户端的启动方法
 51 */
 52 public void start() {
 53 try {
 54 //启动线程,读取服务端发送过来的消息
 55 ServerHandler handler = new ServerHandler();
 56 Thread t = new Thread(handler);
 57 t.start();
 58 /*
 59 * Socket提供的方法:
 60 * OutputStream getOutputStream()
 61 * 该方法会返回一个字节输出流,通过这个流写出的字节都会通过网络发送给远端计算机
 62 *
 63 * 利用流连接,名可以很方便的按行写出一个字符串
 64 */
 65 OutputStream out = socket.getOutputStream();
 66 OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");
 67 BufferedWriter bw = new BufferedWriter(osw);
 68 PrintWriter pw = new PrintWriter(bw,true);
 69 String str;
 70 do {
 71 System.out.println("请输入要发送的信息:");
 72 str = scan.nextLine();
 73 pw.println(str);
 74 }while(!"exit".equals(str));//out.write(str.getBytes());
 75 } catch (Exception e) {
 76 e.printStackTrace();
 77 }
 78 scan.close();
 79 }
 80 public static void main(String[] args) {
 81 Client client =new Client();
 82 client.start();
 83 }
 84 /**
 85 * 该线程用于读取服务端发送过来的消息并输出到控制台
 86 * @author soft01
 87 */
 88 private class ServerHandler implements Runnable{
 89 public void run() {
 90 try {
 91 InputStream is = socket.getInputStream();
 92 InputStreamReader isr = new InputStreamReader(is,"utf-8");
 93 BufferedReader br = new BufferedReader(isr);
 94 String line;
 95 while((line = br.readLine())!=null) {
 96 System.out.println(line);
 97 };
 98 } catch (Exception e) {
 99 e.printStackTrace();
100 }
101 }
102 }
103 }
104
105
106
107 【案例】服务端
108 package socket;
109
110 import java.io.BufferedReader;
111 import java.io.BufferedWriter;
112 import java.io.IOException;
113 import java.io.InputStream;
114 import java.io.InputStreamReader;
115 import java.io.OutputStream;
116 import java.io.OutputStreamWriter;
117 import java.io.PrintWriter;
118 import java.net.ServerSocket;
119 import java.net.Socket;
120 import java.util.Arrays;
121 /**
122 * 聊天室服务端
123 * @author soft01
124 */
125 public class Server {
126 /*
127 * 运行在服务端的ServerSocket主要有两个作用:
128 * 1:向系统申请服务端口,客户端就可以通过这个端口与服务端建立连接;
129 * 2:监听该服务端口,一旦客户端通过该端口请求建立连接,
130 * 那么马上就会实例化一个Socket,通过这个Socket就可以与该客户端进行数据通讯了
131 */
132 private ServerSocket server;
133 /*
134 * 由于ClientHandler时Server的内部类,那么所有的ClientHandler都可以访问到该属性,为此可以作为各ClientHandler的共享数据使用
135 */
136 private PrintWriter [] allOut = new PrintWriter[0];
137 /** 构造方法 */
138 public Server (){
139 try {
140 /*
141 * 实例化的过程需要传入向体同申请的端口号
142 * 若端口已经被系统其他程序占用则会抛出地址被占用的异常,这是我们需要更换其他端口;
143 */
144 System.out.println("正在启动服务端……");
145 server= new ServerSocket(8088);
146 System.out.println("服务端启动完毕");
147 } catch (IOException e) {
148 e.printStackTrace();
149 }
150 }
151 /** 启动方法    */
152 public void start() {
153 try {
154 /*
155 * ServerSocket提供两种方法:
156 * 1:Socket accept()
157 * 该方法是一个阻塞方法,作用是监听申请的服务端口,等待客户端的连接
158 * 一旦一个客户端通过该端口建立连接,那么该方法会返回一个Socket实例,
159 * 通过该Socket实例即可与该客户端进行通讯
160 */
161 while(true) {
162 System.out.println("等待客户端连接……");
163 Socket socket = server.accept();
164 System.out.println("一个客户端连接了!");
165 /**启动一个线程,将该socket传递给线程,使其处理该客户端交互 */
166 ClientHandler ch = new ClientHandler(socket);
167 Thread t1 = new Thread(ch);
168 t1.start();
169 }
170
171 }catch(Exception e) {
172 e.printStackTrace();
173 }
174 }
175
176 public static void main(String[] args) {
177 Server server = new Server();
178 server.start();
179 }
180
181 //内部类
182 private class ClientHandler implements Runnable{
183 private Socket socket;
184 /**构造方法,将socket通过传递参数形式赋值给socket */
185 ClientHandler(Socket socket){
186 this.socket=socket;
187 }
188 public void run() {
189 PrintWriter pw = null;
190 try {
191 /* Socket提供的: InputStream getIntputStream() 通过该方法返回的输入流可以读取到远端发送过来的数据 */
192 InputStream is = socket.getInputStream();
193 InputStreamReader isr= new InputStreamReader(is,"utf-8");
194 BufferedReader br = new BufferedReader(isr);
195 /*通过socket获取输出流,用于给客户端发消息 */
196 OutputStream os = socket.getOutputStream();
197 OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
198 BufferedWriter bw = new BufferedWriter(osw);
199 pw = new PrintWriter(bw,true);
200 //将当前客户端对应的输出流存入共享数组
201 synchronized(allOut) {
202 //1,先扩容
203 allOut = Arrays.copyOf(allOut, allOut.length+1);
204 //2,将输出流放入数组最后一位
205 allOut[allOut.length-1] =pw;
206 }
207 Thread t = Thread.currentThread();
208 String line="";
209 do {
210 line = br.readLine();
211 //    System.out.println("客户端说:"+line);
212 //    //将内容发送给客户端
213 //    pw.println("服务端说:"+line);
214 //3,遍历数组,输出
215 synchronized(allOut) {
216 for(int i=0;i<allOut.length;i++) {
217 allOut[i].println(t.getName()+"说:"+line);
218 }
219 }
220 if(line==null) {
221 System.out.println("一个客户端断开了连接。");
222 }
223 }while(line!=null);
224
225 } catch (Exception e) {
226 e.printStackTrace();
227 }finally {
228 //处理客户端断开连接后的操作:
229 //将当前客户端的输出流从allOut中删除
230 synchronized (allOut) {
231 for(int i=0;i<allOut.length;i++) {
232 if(allOut[i]==pw) {
233 allOut[i]=allOut[allOut.length-1];
234 allOut = Arrays.copyOf(allOut, allOut.length-1);
235 break;
236 }
237 }
238 }
239 //关闭流,释放资源
240 try {
241 socket.close();
242 } catch (IOException e) {
243 e.printStackTrace();
244 }
245 }
246 }
247 }
248 }

原文地址:https://www.cnblogs.com/shijinglu2018/p/9153292.html

时间: 2024-11-02 17:24:29

异常和TCP通讯的相关文章

boost asio 异步实现tcp通讯

---恢复内容开始--- asioboost 目录(?)[-] 一前言 二实现思路 通讯包数据结构 连接对象 连接管理器 服务器端的实现 对象串行化 一.前言 boost asio可算是一个简单易用,功能又强大可跨平台的C++通讯库,效率也表现的不错,linux环境是epoll实现的,而windows环境是iocp实现的.而tcp通讯是项目当中经常用到通讯方式之一,实现的方法有各式各样,因此总结一套适用于自己项目的方法是很有必要,很可能下一个项目直接套上去就可以用了. 二.实现思路 1.通讯包数

推荐一款开源的C#TCP通讯框架

原来收费的TCP通讯框架开源了,这是一款国外的开源TCP通信框架,使用了一段时间,感觉不错,介绍给大家 框架名称是networkcomms 作者开发了5年多,目前已经停止开发,对于中小型的应用场景,够用了. 框架的地址是: https://github.com/MarcFletcher/NetworkComms.Net 界面如下: 点那个Download就可以下载源码了 下载之后,解压缩之后的文件列表如下: 可以用VS打开NetworkCommsDotNet工程文件了 用 vs2010打开,可能

ActiveMQ之 TCP通讯机制

ActiveMQ支持多种通讯协议TCP/UDP等,我们选取最常用的TCP来分析ActiveMQ的通讯机制.首先我们来明确一个概念:  客户(Client):消息的生产者.消费者对ActiveMQ来说都叫作客户.  消息中介(Message broker):接收消息并进行相关处理后分发给消息的消费者. 为了能清楚的描述出ActiveMQ的核心通讯机制,我们选择3个部分来进行说明,它们分别是建立链接.关闭链接.心跳. 一.Client跟activeMQ的TCP通讯的初始化过程分析如下:  (1) A

C#中的TCP通讯与UDP通讯

最近做了一个项目,主要是给Unity3D和实时数据库做通讯接口.虽然方案一直在变:从开始的UDP通讯变为TCP通讯,然后再变化为UDP通讯;然后通讯的对象又发生改变,由与数据库的驱动进行通讯(主动推送数据给驱动,数据库中数据发生变化把数据以UDP报文形式发送客户端)改为与实时数据库进行直接通讯(自己发送报文修改数据库中的数据,自己请求需要获取的数据并接收自己请求的数据):现在这个项目基本完结,由于这个过程既接触到了UDP又接触到了TCP,现在对其进行一番总结. 阅读目录 TCP通讯协议与UDP通

C#TCP通讯框架

开源的C#TCP通讯框架 原来收费的TCP通讯框架开源了,这是一款国外的开源TCP通信框架,使用了一段时间,感觉不错,介绍给大家 框架名称是networkcomms 作者开发了5年多,目前已经停止开发,对于中小型的应用场景,够用了. 框架的地址是: https://github.com/MarcFletcher/NetworkComms.Net 界面如下: 点那个Download就可以下载源码了 下载之后,解压缩之后的文件列表如下: 可以用VS打开NetworkCommsDotNet工程文件了

解决Linux 下server和client 通过TCP通讯:accept成功接收却报错的问题

今天在写简单的TCP通讯例子的时候,遇到了一个问题:server 和client能够连接成功,并且client也能够正常发送,但server就是接收不到,在网上搜索一番后,终于解决了问题.在这里整理如下: 大家要注意的是,一个server端可以连接多个client端,server端的accept()函数负责等待并接收client的连接请求,而且accept()函数将不同client端的sockfd作为返回值.为了保证接收到对应的client端数据,所以在client连接成功且使用recv()函数

&amp;#39;IOKING&amp;#39; TCP Transmission Server Engine (&amp;#39;云猴&amp;#39;&amp;#169;TCP通讯server引擎)(预告版)

关键词: IOKING IOCP TCP  Transmission Server Engine Lock Free Interlocked 云猴完毕portTCP通讯server引擎 无锁 原子锁(函数) 'IOKING' TCP Transmission Server Engine ('云猴'?TCP通讯server引擎)(预告版) 下载连接: http://download.csdn.net/detail/guestcode/7474171 补充: 无锁消息引擎已经完毕: http://b

基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据

最近要在QT下开发Tcp通讯,发送序列化数据以便于接收. 这里涉及到几个问题: 1.QTcpSocket.QTcpServer的通讯 2.QDataStream序列化数据 多的不说,直接上干货!!! 客户端: tcpclient.h 1 #ifndef TCPCLIENT_H 2 #define TCPCLIENT_H 3 4 #include <QMainWindow> 5 #include <qt4/Qt/qtcpsocket.h> 6 #include <Qt/qhos

GCDAsyncSocket类库,IOS下TCP通讯使用心得

关于在IOS下使用Socket进行通讯的技术文章也许诺很久了,今日又是一个还债的日子,网上虽然很多介绍过AsyncSocket或GCDAsyncSocket的文章,但其实就那么一两篇大部分都是转载,于是我义正言辞.慷慨激昂的批判他们这种不负责任的态度,学习,不是给自己学的,是要和大家分享的.技术的共享有利于整体行业的进步,也可以使自身更深入全面的了解. 之前的文章中我们讲到过TCP通讯协议,并且也对其进行了较为详细的介绍和描述,关于TCP通讯的原理此处我们不再赘述,如有需要的看官可自行翻阅本人所