首页 文章 精选 留言 我的

精选列表

搜索[Unicode通信],共10000篇文章
优秀的个人博客,低调大师

高性能网络通信框架Netty-Netty客户端底层与Java NIO对应关系

5.1 Netty客户端底层与Java NIO对应关系 在讲解Netty客户端程序时候我们提到指定NioSocketChannel用于创建客户端NIO套接字通道的实例,下面我们来看NioSocketChannel是如何创建一个Java NIO里面的SocketChannel的。 首先我们来看NioSocketChannel的构造函数: public NioSocketChannel() { this(DEFAULT_SELECTOR_PROVIDER); } 其中DEFAULT_SELECTOR_PROVIDER定义如下: private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider(); 然后继续看 //这里的provider为DEFAULT_SELECTOR_PROVIDER public NioSocketChannel(SelectorProvider provider) { this(newSocket(provider)); } 其中newSocket代码如下: private static SocketChannel newSocket(SelectorProvider provider) { try { return provider.openSocketChannel(); } catch (IOException e) { throw new ChannelException("Failed to open a socket.", e); } } 所以NioSocketChannel内部是管理一个客户端的SocketChannel的,这个SocketChannel就是讲Java NIO时候的SocketChannel,也就是创建NioSocketChannel实例对象时候相当于执行了Java NIO中: SocketChannel socketChannel = SocketChannel.open(); 另外在NioSocketChannel的父类AbstractNioChannel的构造函数里面默认会记录队op_read事件感兴趣,这个后面当链接完成后会使用到: protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { super(parent, ch, SelectionKey.OP_READ); } 另外在NioSocketChannel的父类AbstractNioChannel的构造函数里面设置了该套接字为非阻塞的 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent); this.ch = ch; this.readInterestOp = readInterestOp; try { ch.configureBlocking(false); } catch (IOException e) { ... } } 下面我们看Netty里面是哪里创建的NioSocketChannel实例,哪里注册到选择器的。 下面我们看下Bootstrap的connect操作代码: public ChannelFuture connect(InetAddress inetHost, int inetPort) { return connect(new InetSocketAddress(inetHost, inetPort)); } 类似Java NIO传递了一个InetSocketAddress对象用来记录服务端ip和端口: public ChannelFuture connect(SocketAddress remoteAddress) { ... return doResolveAndConnect(remoteAddress, config.localAddress()); } 下面我们看下doResolveAndConnect的代码: private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) { //(1) final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.isDone()) { if (!regFuture.isSuccess()) { return regFuture; } //(2) return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise()); } ... } } 首先我们来看代码(1)initAndRegister: final ChannelFuture initAndRegister() { Channel channel = null; try { //(1.1) channel = channelFactory.newChannel(); //(1.2) init(channel); } catch (Throwable t) { ... } //(1.3) ChannelFuture regFuture = config().group().register(channel); if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } } } 其中(1.1)作用就是创建一个NioSocketChannel的实例,代码(1.2)是具体设置内部套接字的选项的。 代码(1.3)则是具体注册客户端套接字到选择器的,其首先会调用NioEventLoop的register方法,最后调用NioSocketChannelUnsafe的register方法: public final void register(EventLoop eventLoop, final ChannelPromise promise) { ... AbstractChannel.this.eventLoop = eventLoop; if (eventLoop.inEventLoop()) { register0(promise); } else { try { eventLoop.execute(new Runnable() { @Override public void run() { register0(promise); } }); } catch (Throwable t) { ... } } } 其中 register0内部调用doRegister,其代码如下: protected void doRegister() throws Exception { boolean selected = false; for (;;) { try { //注册客户端socket到当前eventloop的selector上 selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); return; } catch (CancelledKeyException e) { ... } } } 到这里代码(1)initAndRegister的流程讲解完毕了,下面我们来看代码(2)的 public final void connect( final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) { ... try { ... boolean wasActive = isActive(); if (doConnect(remoteAddress, localAddress)) { fulfillConnectPromise(promise, wasActive); } else { 。。。 } } catch (Throwable t) { ... } } 其中doConnect代码如下: protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { ... boolean success = false; try { //2.1 boolean connected = SocketUtils.connect(javaChannel(), remoteAddress); //2.2 if (!connected) { selectionKey().interestOps(SelectionKey.OP_CONNECT); } success = true; return connected; } finally { if (!success) { doClose(); } } } 其中2.1具体调用客户端套接字的connect方法,等价于Java NIO里面的。 代码2.2 由于connect 方法是异步的,所以类似JavaNIO调用connect方法进行判断,如果当前没有完成链接则设置对op_connect感兴趣。 最后一个点就是何处进行的从选择器获取就绪的事件的,具体是在该客户端套接关联的NioEventLoop里面的做的,每个NioEventLoop里面有一个线程用来循环从选择器里面获取就绪的事件,然后进行处理: protected void run() { for (;;) { try { ... select(wakenUp.getAndSet(false)); ... processSelectedKeys(); ... } catch (Throwable t) { handleLoopException(t); } ... } } 其中select代码如下: private void select(boolean oldWakenUp) throws IOException { Selector selector = this.selector; try { ... for (;;) { ... int selectedKeys = selector.select(timeoutMillis); selectCnt ++; ... } catch (CancelledKeyException e) { ... } } 可知会从选择器选取就绪的事件,其中processSelectedKeys代码如下: private void processSelectedKeys() { ... processSelectedKeysPlain(selector.selectedKeys()); ... } 可知会获取已经就绪的事件集合,然后交给processSelectedKeysPlain处理,后者循环调用processSelectedKey具体处理每个事件,代码如下: private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { ... try { //(3)如果是op_connect事件 int readyOps = k.readyOps(); if ((readyOps & SelectionKey.OP_CONNECT) != 0) { int ops = k.interestOps(); ops &= ~SelectionKey.OP_CONNECT; k.interestOps(ops); //3.1 unsafe.finishConnect(); } //4 if ((readyOps & SelectionKey.OP_WRITE) != 0) { ch.unsafe().forceFlush(); } //5 if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { unsafe.read(); } } catch (CancelledKeyException ignored) { unsafe.close(unsafe.voidPromise()); } } 代码(3)如果当前事件key为op_connect则去掉op_connect,然后调用NioSocketChannel的doFinishConnect: protected void doFinishConnect() throws Exception { if (!javaChannel().finishConnect()) { throw new Error(); } } 可知是调用了客户端套接字的finishConnect方法,最后会调用NioSocketChannel的doBeginRead方法设置对op_read事件感兴趣: protected void doBeginRead() throws Exception { ... final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { selectionKey.interestOps(interestOps | readInterestOp); } } 这里interestOps为op_read,上面在讲解NioSocketChannel的构造函数时候提到过。 代码(5)如果当前是op_accept事件说明是服务器监听套接字获取到了一个链接套接字,如果是op_read,则说明可以读取客户端发来的数据了,如果是后者则会激活管线里面的所有handler的channelRead方法,这里会激活我们自定义的NettyClientHandler的channelRead读取客户端发来的数据,然后在向客户端写入数据。 5.2 总结 本节讲解了Netty客户端底层如何使用Java NIO进行实现的,可见与我们前面讲解的Java NIO设计的客户端代码步骤是一致的,只是netty对其进行了封装,方便了我们使用,了解了这些对深入研究netty源码提供了一个骨架指导。 原文发布时间为:2018-06-8 本文来自云栖社区合作伙伴“并发编程网 - ifeve.com”,了解相关信息可以关注“并发编程网 - ifeve.com”。

优秀的个人博客,低调大师

安卓客户端和服务器端的通信(勘误填坑版)

版权声明:本文可能为博主原创文章,若标明出处可随便转载。 https://blog.csdn.net/Jailman/article/details/78328405 一个很基础的socket链接示例,仅用作测试和学习使用 首先是服务器端的代码,一个标准的socket server,绑定本地的54321端口 package online.geekgalaxy.test; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketServer implements Runnable { public void run() { try { //创建ServerSocket ServerSocket serverSocket = new ServerSocket(54321); while (true) { //接受客户端请求 Socket client = serverSocket.accept(); System.out.println("accept"); try { //接收客户端消息 BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); String str = in.readLine(); System.out.println("read:" + str); //向服务器发送消息 PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(client.getOutputStream())),true); out.println("server message"); //关闭流 out.close(); in.close(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } finally { //关闭 client.close(); System.out.println("close"); } } } catch (Exception e) { System.out.println(e.getMessage()); } } //main函数,开启服务器 public static void main(String a[]) { Thread desktopServerThread = new Thread(new SocketServer()); desktopServerThread.start(); } } 附加一个python的服务端 #!/usr/bin/python # -*- coding: UTF-8 -*- import socket s = socket.socket() host = socket.gethostname() port = 54321 s.bind((host, port)) s.listen(5) while True: c, addr = s.accept() print 'Connect from ', addr c.send('Welcome!') c.close() 然后是安卓客户端,很简单,但是连接时不能使用127.0.0.1,所以使用了局域网的10段地址 manifest文件 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="online.geekgalaxy.socketclient"> <uses-permission android:name="android.permission.INTERNET" /> <uses-sdk android:minSdkVersion="5" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>mainactivity文件,使用了一种不是特别推荐的方式在新的API基础上运行socket客户端命令 package online.geekgalaxy.socketclient; import android.os.StrictMode; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements Runnable{ // @Override // protected void onCreate(Bundle savedInstanceState) { // super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); // } private final String DEBUG_TAG = "MainActivity"; private TextView mTextView = null; private EditText mEditText = null; private Button mButton = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); mButton = (Button)findViewById(R.id.Button01); mTextView = (TextView)findViewById(R.id.TextView01); mEditText = (EditText)findViewById(R.id.EditText01); //登陆 mButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { run(); } }); } @Override public void run() { Socket socket = null; String message = mEditText.getText().toString() + "/r/n"; try { //创建Socket // socket = new Socket("192.168.1.110",54321); socket = new Socket("10.9.3.132", 54321); //IP:10.14.114.127,端口54321 //向服务器发送消息 PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); out.println(message); //接收来自服务器的消息 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String msg = br.readLine(); if (msg != null) { mTextView.setText(msg); } else { mTextView.setText("数据错误!"); } //关闭流 out.close(); br.close(); //关闭Socket socket.close(); } catch (Exception e) { // TODO: handle exception Log.e(DEBUG_TAG, e.toString()); } } } mainactivity推荐的写法,使用runnable,是上面代码的替代方案 package online.geekgalaxy.socketclient; //import android.os.StrictMode; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity{ // @Override // protected void onCreate(Bundle savedInstanceState) { // super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); // } private final String DEBUG_TAG = "MainActivity"; private TextView mTextView = null; private EditText mEditText = null; private Button mButton = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); // StrictMode.setThreadPolicy(policy); mButton = (Button)findViewById(R.id.Button01); mTextView = (TextView)findViewById(R.id.TextView01); mEditText = (EditText)findViewById(R.id.EditText01); //登陆 mButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // run(); new Thread(runnable).start(); } }); } Runnable runnable = new Runnable() { @Override public void run() { Socket socket; String message = mEditText.getText().toString() + "/r/n"; try { //创建Socket // socket = new Socket("192.168.1.110",54321); socket = new Socket("10.9.3.132", 54321); //IP:10.14.114.127,端口54321 //向服务器发送消息 PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); out.println(message); //接收来自服务器的消息 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String msg = br.readLine(); if (msg != null) { mTextView.setText(msg); } else { mTextView.setText("数据错误!"); } //关闭流 out.close(); br.close(); //关闭Socket socket.close(); } catch (Exception e) { // TODO: handle exception Log.e(DEBUG_TAG, e.toString()); } } }; } 然后是layout文件,里边的string被提取了出来,自己补全即可 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/TextView01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/servermessage" /> <EditText android:id="@+id/EditText01" android:text="@string/sendmessage" android:layout_width="fill_parent" android:layout_height="wrap_content"> </EditText> <Button android:id="@+id/Button01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/buttonsend" /> </LinearLayout> build.gradle还是贴出来吧 apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion "26.0.2" defaultConfig { applicationId "online.geekgalaxy.socketclient" minSdkVersion 25 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.+' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' }

优秀的个人博客,低调大师

世界末日计划:欧盟为毁灭性电力和通信网络攻击做好准备

来自30个国家的超700名安全专家,聚焦电力中断、对无人机的攻击和勒索软件 4月起,超过700名安全专家一直奋战在虚拟网络安全危机的第一线,这是欧盟迄今为止最大型的防御演练的一部分。以电力中断、无人机和勒索软件为特征,一系列虚拟攻击剑指欧洲数字网络。 长达7个月的演练在本周达到高潮,从中获取的各种经验将在参与者中共享,期望能改善防御系统。专家警告称,包括卫星、核电站等,对任意数量此类系统的攻击,都有可能造成全球性灾难。“网络欧洲2016”涉及30个国家的300多家企业,意图保卫欧洲数字单一市场。 欧盟网络和信息安全机构(ENISA)组织了此次演练,在一份声明中,该机构称,“计算机安全攻击越来越多地被用于执行工业侦察,主导虚假情报活动,操纵股票市场,泄露敏感信息,篡改客户数据,破坏关键基础设施。”牵涉到的组织包括IT安全公司、银行、能源公司和网络安全机构。 ENISA称,本次演练受圣诞期间欧洲某国(乌克兰)断电事件,以及对欧盟外部产出技术的依赖等事实的启发,描绘了一幅非常黑暗恐怖的场景。演练涉及针对无人机、云技术、移动恶意软件和物联网等多种不同威胁。 演员、虚拟媒体、公司和社交媒体也全都参与进来以使场景尽量逼真。ENISA执行总裁乌多·赫姆布雷希特说:“我们比以往准备充分,但这不意味着我们已经做到够好,工作必须持续下去。” 网络攻击比以前更复杂高端了。网络安全不是一种状态,是一个过程。 演练结果将在2018年下一次网络欧洲演练前被分析总结并吸收。进行虚拟演练以应对网络攻击的做法不仅仅有欧盟一家。去年,美国政府研究部门——DARPA,启动了一项针对全美断电威胁的新计划。专家之前就警告过,在保护卫星和其他空间基础设施免受恶意攻击或恶意使用上,政府和企业做得还远远不够。 英国智库查塔姆研究所最近的一份报告指出,对宇宙飞船和卫星的黑客攻击后果,可导致“全球性灾难”。该研究所另一份类似报告,详细描述了对核电厂进行的大型网络攻击的风险。 电厂并未准备好应对网络攻击 一份报告警告道:全世界的核电厂都在拒绝严重网络攻击的风险。该研究宣称,大多数国家的民用核设施对此类攻击是没有准备的。攻击后果很可能是毁灭性的,因为即便是小范围的攻击,也会向当地释放出致命辐射。 报告宣称,网络罪犯有可能触发与2011年福岛第一核电站泄漏事故类似的事件。近16000人在那场自然灾害及其后续破坏中丧生。查塔姆研究所发表的报告,对电厂网络18个月内的安全状况进行了调查,援引了全球50起电厂安全事件,其中很大一部分都是保密事件。 该报告发现,全球核电厂都缺乏安全协议,这一情况十分令人担忧。举个例子,标准出厂口令,比如“1234”,能在控制电厂关键系统的诸多电脑系统上找到。 上周,国际原子能机构(IAEA)总干事天野之弥证实,数年前某核设施成为了网络攻击的目标。美国宾夕法尼亚州的安全专家们开发出新型“移动目标防御”系统以闪躲网络攻击。 新计算机系统会在感受到恶意扫描时抛出诱饵,重定向黑客到模拟真实场景的一个网络中。这些“影子网络”可以模拟复杂网络结构,诱骗黑客相信自己已经成功获取到可用信息。名为“快速攻击检测隔离和描述”(RADICS),其目标是开发出自动化掉电处理系统。 这些系统应有助于公共事业工程师们在遭攻击后7天内恢复供电。DARPA项目经理称:“如果今天有组织良好的网络攻击针对国家电网展开,用于恢复电力所耗费的时间,将给国家安全带来巨大挑战。” “除了严重的国内影响,包括经济和人力损失,电网长时间瘫痪还将损害军事动员和后勤,伤及政府调遣军队或处理国际危及的能力。” 作者:nana 来源:51CTO

优秀的个人博客,低调大师

Kubernetes1.7正式发布,优化了可扩展性,安全增强和网络通信策略

Kubernetes 1.7已经发布本文Ghostcloud将为大家深度分析新版本的可扩展性和安全性以及一系列新特性。 Kubernetes 1.7包括了4个稳定特性7个公测版和19个内测版有来自谷歌、CoreOS、Mirantis、Red Hat、微软等公司的370余人参与了这个新版本的发布。 一般情况下内测版本中的特性不会被默认开启它们不会被官方社区认为是“生产就绪”了的产品功能但用户可以选择使用它们。公测版的功能则是经过大量用户测试的默认开启在后面的版本中它们可能会有改变。 4个稳定的特性意味着这部分产品内容已经被证明准备就绪禁得住考验并将在许多后续版本中沿用 1、用于限制容器网络流量的网络策略API2、用于负载平衡器的源IP处理3、StorageOS卷插件4、云存储指标 改进的可扩展性旨在扩大Kubernetes的范围和功能不会使核

优秀的个人博客,低调大师

网口温湿度记录仪IP通信踩坑:TCP长连接断线排查与优化

某电力调度机房部署了16台网口温湿度记录仪,采集平台采用TCP长连接方式(每台设备保持一个持久连接,周期性发送Modbus功能码03读取寄存器)。上线首周运行平稳,但从第二周开始,运维陆续反馈:部分设备数据间歇性中断,持续30秒~5分钟不等后自动恢复,平台日志中反复出现 ConnectionResetError 和 BrokenPipeError。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册