2023年7月15日发(作者:)
Socket与SocketChannel⽹络由下往上分为物理层、数据链路层、⽹络层、传输层、会话层、表⽰层和应⽤层。 通过初步的了解,我知道IP协议对应于⽹络层,TCP协议对应于传输层,⽽HTTP协议对应于应⽤层,三者从本质上来说没有可⽐性,socket则是对 TCP/IP协议的封装和应⽤(程序员层⾯上)。也可以说,TPC/IP协议是传输层协议,主要解决数据如何在⽹络中传输,⽽HTTP是应⽤层协议,主要 解决如何包装数据。socket是对TCP/IP协议的封装,Socket本⾝并不是协议,⽽是⼀个调⽤接⼝(API)。 通过Socket,我们才能使⽤TCP/IP协议。
⼀、利⽤Socket建⽴⽹络连接的步骤
建⽴Socket连接⾄少需要⼀对套接字,其中⼀个运⾏于客户端,称为ClientSocket ,另⼀个运⾏于服务器端,称为ServerSocket 。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
1、服务器监听:服务器端套接字并不定位具体的客户端套接字,⽽是处于等待连接的状态,实时监控⽹络状态,等待客户端的连接请求。
2、客户端请求:指客户端的套接字提出连接请求,要连接的⽬标是服务器端的套接字。为此,客户端的套接字必须⾸先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端⼝号,然后就向服务器端套接字提出连接请求。
3、连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建⽴⼀个新的线程,把服务器端套接字的描述发给 客户端,⼀旦客户端确认了此描述,双⽅就正式建⽴连接。⽽服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
⼆、HTTP链接的特点
HTTP协议即超⽂本传送协议(Hypertext Transfer Protocol ),是Web联⽹的基础,也是⼿机联⽹常⽤的协议之⼀,HTTP协议是建⽴在TCP协议之上的⼀种应⽤。HTTP连接最显著的特点是客户端发送的每次请求 都需要服务器回送响应,在请求结束后,会主动释放连接。从建⽴连接到关闭连接的过程称为“⼀次连接”。
三、TCP和UDP的区别
1、TCP是⾯向链接的,虽然说⽹络的不安全不稳定特性决定了多少次握⼿都不能保证连接的可靠性,但TCP的三次握⼿在最低限度上(实际上也很⼤程度上 保证了)保证了连接的可靠性;⽽UDP不是⾯向连接的,UDP传送数据前并不与对⽅建⽴连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正 确接收,当然也不⽤重发,所以说UDP是⽆连接的、不可靠的⼀种数据传输协议。
2、也正由于1所说的特点,使得UDP的开销更⼩数据传输速率更⾼,因为不必进⾏收发数据的确认,所以UDP的实时性更好。四、Socket、SocketChannel有什么区别Socket、SocketChannel⼆者的实质都是⼀样的,都是为了实现客户端与服务器端的连接⽽存在的,但是在使⽤上,却有很⼤的区别。具体如下:1.所属包不同Socket在包中,⽽SocketChannel在包中。2.异步⽅式不同从包的不同,我们⼤体可以推断出他们主要的区别:Socket是阻塞连接(当然我们可以⾃⼰实现⾮阻塞),SocketChannel可以设置⾮阻塞连接。使⽤ServerSocket、Socket类时,服务端Socket往往要为每⼀个客户端Socket分配⼀个线程,⽽每⼀个线程都有可能处于长时间的阻塞状态中。过多的线程也会影响服务器的性能(可以使⽤线程池优化,具体看这⾥:如何编写多线程Socket程序)。⽽使⽤SocketChannel、ServerSocketChannel类可以⾮阻塞通信,这样使得服务器端只需要⼀个线程就能处理所有客户端socket的请求。3.性能不同⼀般来说使⽤SocketChannel会有更好的性能。其实,Socket实际应该⽐SocketChannel更⾼效,不过由于使⽤者设计等原因,效率反⽽⽐直接使⽤SocketChannel低。4.使⽤⽅式不同Socket、ServerSocket类可以传⼊不同参数直接实例化对象并绑定ip和端⼝,如:Socket socket = new Socket("127.0.0.1", "8000");ServerSocket serverSocket = new ServerSocket("8000");⽽SocketChannel、ServerSocketChannel类需要借助Selector类控制,如:private SocketChannel mSocketChannel;private Selector mSelector;private static boolean sIsGoOn = true;private static final int MAX_BUFFER_SPACE = 2048;/** *
建⽴ Socket
连接 * @param host
服务器 ip * @param port
服务器端⼝号 * @param port
服务器端⼝号 * @return
返回建⽴ socket
连接的结果i */public boolean open(String host, String port) { if (y(host) || y(port)) { LogUtil.e( "host or port error."); return false; } try { mSelector = (); mSocketChannel = SocketChannel .open(new InetSocketAddress(host, nt(port))); ureBlocking(false);// 设置为⾮阻塞⽅式,如果为true 那么就为传统的阻塞⽅式 er(mSelector, _READ | _WRITE);//注册读就绪事件和写就绪事件 } catch (IOException e) { tackTrace(); return false; } return true;}/** *
发送报⽂ * @param sendPacket
待发送的报⽂ * @return
返回发送结果 */public int sendPacket(byte[] sendPacket) { int count = 0; try { sIsGoOn = true; while (sIsGoOn && () > 0) { Iterator iterator = edKeys().iterator(); while (sIsGoOn && t()) { SelectionKey selectionKey = (SelectionKey) (); (); if (able()) { SocketChannel socketChannel = (SocketChannel) l(); ByteBuffer byteBuffer = (sendPacket, 0, ); count = (byteBuffer); LogUtil.i( "Send ok."); return count; } LogUtil.i( "sendPacket: "); edKeys().remove(selectionKey); } } } catch (IOException e) { tackTrace(); return -1; } return count;}/** *
接收来⾃服务器的报⽂ * @return
返回接收的报⽂ */public byte[] receivePacket() { byte[] receivedPacket = null; int count; try { sIsGoOn = true; while (sIsGoOn && () > 0) { Iterator iterator = edKeys().iterator(); Iterator iterator = edKeys().iterator(); while (sIsGoOn && t()) { SelectionKey selectionKey = (SelectionKey) (); (); try { if (able()) { SocketChannel socketChannel = (SocketChannel) l(); ByteBuffer byteBuffer = te(MAX_BUFFER_SPACE); (); count = (byteBuffer); (); if (count > 0) { receivedPacket = new byte[count]; opy((), 0, receivedPacket, 0, count); } break; } } catch (CancelledKeyException e) { (); LogUtil.e( sage()); } edKeys().remove(selectionKey); } if (receivedPacket != null) { break; } } } catch (IOException e) { tackTrace(); } return receivedPacket;}/** *
关闭 Socket
连接 */public void close() { try { if (mSocketChannel != null && ected()) { Connect(); (); sIsGoOn = false; (); LogUtil.i( "close: "); } } catch (IOException e) { tackTrace(); }}这些操作均需要在⼦线程进⾏private static final int RETRY_MAX_COUNT = 6;private static final String CARD_ERROR = "cardError";private byte[] mReceivePacket;/** *
建⽴ Socket
连接,⽤于发送报⽂ */private PacketSocket mPacketSocket;private IPacketModelInterface mModelInterface;/** *
临时使⽤ */private CommunicationInfo mCommunicationInfo;/** *
尝试发送的次数 */private int mSendNum;private BasePacket mPacket;public PacketTransferTask(Context context, IPacketModelInterface modelInterface, BasePacket packet) { mPacketSocket = new PacketSocket(); mCommunicationInfo = new CommunicationInfo(context); mPacket = packet; mModelInterface = modelInterface;}@Overrideprotected String doInBackground(byte[]... sendPacket) { LogUtil.i( "doInBackground: sendPacket" + oHexString(sendPacket[0])); while (sumeData().getCardType() == _TYPE_IC && !erse) { int flag = sumeData().getSearchCardResponse(); if (flag != 0 && flag != 1) { return null; } if (sumeData().isCanSendPacket()) { LogUtil.i( "generatePacket again"); acket(); sendPacket[0] = tePacket(); break; } } publishProgress(_STATUS_CONNECTING); String ip = tIP(); String port = tPort(); if (ip == null || port == null) { ip = reHostIP(); port = reHostPort(); mSendNum = 3; if (ip == null || port == null) { LogUtil.e( "ip or port is null"); return _ERROR_IP_PORT; } } while (mSendNum < RETRY_MAX_COUNT) { if (isCancelled()) { return null; } if (mSendNum == 3) { ip = reHostIP(); port = reHostPort(); } if (!(ip, port)) { LogUtil.e( mSendNum + " open failed"); mSendNum++; } else { LogUtil.e( mSendNum + " open success"); break; } } if (mSendNum == 6) { LogUtil.e( "socket open failed."); return _ERROR_CONNECT; } } publishProgress(_STATUS_SENDING); if (sendPacket[0] != null && cket(sendPacket[0]) <= 0) { LogUtil.e( "send packet failed."); return _ERROR_SEND; } publishProgress(_STATUS_RECEIVERING); try { mReceivePacket = ePacket(); } catch (ClosedSelectorException e) { LogUtil.e( sage()); } if ((mReceivePacket == null) || ( <= 0)) { LogUtil.e( "receive packet failed."); return _ERROR_RECEIVER; } int isCard = sumeData().getCardType(); LogUtil.i( "isCard: " + isCard); LogUtil.i( "sIsReverse: " + erse); if (isCard == _TYPE_IC && !erse) { String domain39Data = ConvertUtil .bytesToString(ackDomainData(39, mReceivePacket)); String domain55Data = ConvertUtil .bytesToHexString(ackDomainData(55, mReceivePacket)); int result; result = sumeData().getSearchCardResponse(); if (result != 1) { tance().setRequestOnline(true, domain39Data, domain55Data); } while (true) { if (!_CODE_(domain39Data)) { sumeData().setApproval(true); break; } result = sumeData().getSearchCardResponse(); if (result != 1 && result != 0) { verseInfo(_CODE_96); return CARD_ERROR; } else if (result != 0) { break; } if (sumeData().getConsumeType() == _BALANCE_INQUIRY) { break; } } } return _SUCCESS;}@Overrideprotected void progress) { ressUpdate(progress); PacketSocketProgress(progress[0]);}@Overrideprotected void onPostExecute(String socketResult) { Execute(socketResult); if (isCancelled()) { return; } } LogUtil.i( "onPostExecute: socketResult" + socketResult); LogUtil.i( "onPostExecute: receivePacket" + oHexString(mReceivePacket)); ivePacket(socketResult, mReceivePacket); ();}下⾯是SocketChannel⽅式需要⽤到的⼏个核⼼类:
ServerSocketChannel
ServerSocket的替代类, ⽀持阻塞通信与⾮阻塞通信。
SocketChannel
Socket的替代类, ⽀持阻塞通信与⾮阻塞通信。
Selector
为ServerSocketChannel监控接收客户端连接就绪事件, 为SocketChannel监控连接服务器读就绪和写就绪事件。
SelectionKey
代表ServerSocketChannel及SocketChannel向Selector注册事件的句柄。当⼀个
SelectionKey对象位于Selector对象的selected-keys集合中时,就表⽰与这个SelectionKey对象相关的事件发⽣了。
在SelectionKey类中有⼏个静态常量:
_ACCEPT,客户端连接就绪事件,等于监听(),返回⼀个socket。
_CONNECT,准备连接服务器就绪,跟上⾯类似,只不过是对于socket的 相当于监听了t()。
_READ,读就绪事件, 表⽰输⼊流中已经有了可读数据, 可以执⾏读操作。
_WRITE,写就绪事件, 表⽰可以执⾏写操作。
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689409100a243380.html
评论列表(0条)