摘要:编程的核心是通道和选择器,选择器通过不断的轮询来执行相应的功能。所以我们需要捕捉这个异常并开始重新连接。如果客户端关闭了,服务器也应该主动关闭它的数据库代码和实体类。如果您仍然想实现数据库代码,请
物联网防御终于结束了。写下自己的网络编程代码,重新连接代码,写很久。试试catch可以这样用!
学习地址:https://www.bilibili.com/video/BV1gz4y1C7RK
项目结构:
1.服务器代码:包服务器;进口商品。用户;导入实用程序。JdbcUtil导入Java . io . io exception;导入Java . net . inetsocketaddress;导入Java . nio . byte buffer;导入Java . nio . channels . *;导入Java . nio . charset . charset;导入Java . text . simple date format;导入Java . util . iterator;导入Java . util . scanner;导入Java . util . set;公共类聊天服务器{public void stratserver (intport)抛出IO异常{//soket channel client channel//创建服务器端通道server socket channel server socket channel = server socket channel . open();//非阻塞模式serversocketchannel . configure blocking(false);//Create buffer byte buffer byte buffer = byte buffer . allocate(1024);//绑定端口serversocketchannel . bind(newinetsocketaddress(port));//创建一个选择器Selector = Selector . open();//注册通道serversocketchannel.register(选择器,selection key . op _ accept);//carousel query system . out . println("智能水表服务器(port:" +port+")已启动");//如果有就绪通道,select方法返回1 while(true){ while(selector . select()> 0){//因为有多个通道,所以采用set获取所有就绪通道//并将所有就绪通道收集到key中;set选择键= selector . selected keys();//selectedKeys所有就绪键集合//将其变成集合迭代器iterator = selection keys . iterator();while(iterator . has next()){ selection key selection key = iterator . next();//有人来连接if(selection key . is acceptable()){ accept operator(服务器套接字通道,选择器);}//已经被else if(selection key . is readable()){ read operator(selector,selection key);}//返回水表数据else if(selection key . is writeable()){ write operator(selector,selection key);} iterator . remove();} } } }//处理服务器写事件私有Void写操作符(选择器Selector,选择键选择键){ try {//有通道写,取出可写通道socket channel socket channel =(socket channel)选择键. channel();//设计一个非阻塞的套接字通道。配置阻塞(假);socket . write(charset . for name(" UTF -8 ")。encode("数据库保存成功!"));//在选择器上重新注册通道,设计监听socket channel . register(selector,selection key . op _ read);} catch(io exception e){ e . printstacktrace();} }//处理read事件私有void read运算符(选择器selector,选择键选择键)抛出IO异常{ try {//Get ready channel socket channel =(socket channel)选择键. channel();//设计缓冲区byte buffer buffer = byte buffer . allocate(1024);//循环读取客户端数据int length = 0;字符串msg =if((length = socket channel . Read(buffer))> 0){//读入缓冲区//切换模式buffer . flip();msg+=Charset.forName("UTF-8 ")。解码(缓冲);//从缓冲区获取数据并解码} system . out . println(msg);string str[]= msg . split(":");string temp = str[1];String str2[]=temp.split("、);simple date format tempDate = new simple date format(" yyyy -MM-DD HH:mm:ss ");string datetime = tempdate . format(new Java . util . date());JdbcUtil.find(新用户(str2[0],str2[1],str2[2],datetime));//在选择器上重新注册通道,设计监听socket channel . register(selector,selection key . op _ write);} catch(io exception e){ selection key . cancel();selectionKey.channel()。close();System.out.println("客户端断开连接,我已经主动关闭");}//光广播给其他用户//if(msg . length()> 0){//system . out . println(msg);// castOtherClient(msg,selector,socket channel);//} }//广播给其他客户端//private void castotherclient(string msg,selector selector,Socket Socket Channel)抛出IO异常{/////Get all ready Channel//set selection key set = selector . keys();//循环通道//for(选择键选择键:选择键集){获取每个通道//通道tarchannel =选择键.通道();//不要给自己发消息//if(socket channel & & tarchannel的tar channel实例!= socket channel){//((socket channel)tar channel)。write(Charset.forName("UTF-8 ")。编码(消息));//对传输的数据进行编码,对传输的数据进行解码//}/}//处理接收状态的通道是Private Void Accept Operator(Server Socket Channel Server Socket Channel,Selector selector) {try {// Get连接Socket Channel Socket Channel = Server Socket Channel . Accept();//设计一个非阻塞的套接字通道。配置阻塞(假);//注册通道socketchannel.register(选择器,selection key . op _ read);//回复客户端消息socket channel . write(charset . forname(" UTF -8 ")。encode("您已经成功连接到服务器了!"));} catch(io exception e){ e . printstacktrace();} } public static void main(String[]args)抛出IOException { new ChatServer()。StratServer(7890);}}解释:我的readOperator函数负责从客户端读取信息。Nio编程的核心是通道和选择器,选择器通过不断的轮询来执行相应的功能。我加入了这个项目的数据库。如果我收到客户信息,我会将它保存在数据库中。
2.客户代码2.1。负责发送的主客户端
打包客户端;导入Java . io . io exception;导入Java . net . inetsocketaddress;导入Java . nio . byte buffer;导入Java . nio . channels . selection key;导入Java . nio . channels . selector;导入Java . nio . channels . socket channel;导入Java . nio . charset . charset;导入Java . util . scanner;类chat client { public void start client(string name)抛出io异常,中断异常{//创建通道绑定主机和端口套接字通道套接字通道= nullsocket channel = socket channel . open(new InetSocketAddress(" 127 . 0 . 0 . 1 ",7890));//接受服务器响应的数据选择器Selector = Selector . open();socket channel . configure blocking(false);socketChannel.register(选择器,SelectionKey。OP _ READ);//创建线程new thread(new client thread(selector))。start();//负责获取服务器数据//将数据System.out.println发送到服务器(“请输入抄表数、抄表水量、抄表人(抄表时间自动生成)(请在1分钟内完成)”);Scanner scanner =新扫描仪(system . in);while(scanner . has nextline()){ byte buffer byte buffer = byte buffer . allocate(1024);string str = scanner . nextline();//键盘获取输入内容if(str . length()> 0){ socket channel . write(charset . forname(" UTF -8 ")。encode ("client:" +name+":"+str+"(加载的数据库)");//system . out . println(charset . for name(" ut F-8 ")。encode(name+":"+str));}//设计非阻塞模式socket channel . configure blocking(false);//Design buffer } } public static void main(string[]args)ThrowsioException,interrupted exception { newchatclient()。start client(“GX”);}} 2.2.负责接收服务器信息的客户端线程
打包客户端;导入Java . io . io exception;导入Java . net . connect exception;导入Java . net . inetsocketaddress;导入Java . nio . byte buffer;导入Java . nio . channels . selection key;导入Java . nio . channels . selector;导入Java . nio . channels . socket channel;导入Java . nio . charset . charset;导入Java . util . iterator;导入Java . util . set;公共类ClientThread实现Runnable { private Selector Selector;ClientThread(选择器Selector){ this . Selector = Selector;} @覆盖public void run(){//while(true){ for(;;){ try { int length = selector . select();if(length = = 0){ continue;}//获取所有通道就绪状态set selection keys = selector . selected keys()in key;//selectedKeys所有就绪键集合//将其变成集合迭代器iterator = selection keys . iterator();while(iterator . has next()){ selection key selection key = iterator . next();if(selection key . is readable()){ read operator(selector,selection key);} iterator . remove();} } catch(io exception | interrupted exception e){ e . printstacktrace();} } }//处理私有void读操作符(选择器selector,选择键选择键)抛出中断异常{ try {//get ready channel socket channel socket channel =(socket channel)选择键. channel();//设计缓冲区byte buffer buffer = byte buffer . allocate(1024);//循环读取客户端数据int length = 0;字符串msg =if((length = socket channel . Read(buffer))> 0){//读入缓冲区//切换模式buffer . flip();msg+= Charset.forName("UTF-8 ")。解码(缓冲);//从缓冲区获取数据并解码} system . out . println(msg);//在选择器上重新注册通道,设计监听socket channel . register(selector,selection key . op _ read);} catch(io exception e){ selection key . cancel();System.out.println("服务器中断,准备重新连接");while (true){ try { new ChatClient()。start client(" GX ");} catch(io exception io exception){ system . out . println("重新连接(5s)");//io exception . printstacktrace();thread . sleep(5000);继续;}}}} 3.钥匙重新连接代码说明1重新连接代码说明
如果服务器突然关闭,如果它向上抛出,而不是尝试在这里捕获异常,客户端将因服务器异常关闭而挂断,并且不会重新连接。所以我们需要捕捉这个异常并开始重新连接。我写了一个无限循环,一直连接。如果我不能连接,他仍然会报告一个错误,所以如果我不能连接,我必须捕捉一个异常。否则,程序会报告一个错误,所以如果捕获连接没有连接,继续执行while循环,直到我连接到服务器。
如果客户端关机,服务器也要主动把他关掉。
4数据库代码和实体类:如果您仍然想实现数据库代码,请
评论前必须登录!
注册