iOS AsyncSocket 與 Java Netty 的簡單socket使用
這兩天簡單看了一下Netty架構的東西。Netty提供非同步、事件驅動的網路應用程式架構和工具,用以快速開發高效能、高可靠性的網路伺服器和用戶端程式。也就是說,Netty 是一個基於NIO的客戶,伺服器端編程架構,使用Netty 可以確保你快速和簡單的開發出一個網路應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網路應用的編程開發過程,例如,TCP和UDP的socket服務開發。 所以參照官方介紹 AsyncSocket 是基於CFSocket與CFStream封裝的TCP/IP socket的網路程式庫,它提供了非同步作業,本地cocoa類的delegate支援。主要關鍵特新如下:1.隊列的可選逾時的非阻塞的讀和寫。比如:你告訴它讀寫的內容,他將在完成的時候通知你.2.socket的自動接收。如果你告訴它接受串連,它將為每個串連建立新的執行個體供你調用。你也可以選擇立即中斷連線。3.支援Delegate,delegate方法中包含錯誤、串連,接收,完整的讀寫、進度、以及中斷連線。4.不基於線程(thread)而基於Run-loop.雖然你可以主線程或者子線程中可以使用,但是木有必要。它使用NSRunLoop非同步呼叫委託的方法。委託方法包括一個socket參數,允許區分多個執行個體。5.自封裝在一個類中。你不需要操作流或Socket。它會自己處理。6.支援基於IPv4、IPv6的TCP流。 github地址: 當然首先第一步就是下載和安裝Netty和AsyncSocket。 第二步:服務端的建立:1.HelloServer
package com.nettypro.io;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;public class HelloServer { /* * 建立服務端監聽連接埠 */ private static final int portNumber = 8080; public static void main(String[] args) throws InterruptedException { EventLoopGroup boosGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(boosGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.childHandler(new HelloServerInitializer()) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6); //伺服器綁定連接埠監聽 ChannelFuture channelFuture = bootstrap.bind(portNumber).sync(); //監聽伺服器關閉監聽 channelFuture.channel().closeFuture().sync(); }finally{ boosGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } }}
2.HelloServerInitializer
package com.nettypro.io;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelPipeline;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.DelimiterBasedFrameDecoder;import io.netty.handler.codec.Delimiters;import io.netty.handler.codec.string.StringDecoder;import io.netty.handler.codec.string.StringEncoder;public class HelloServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel arg0) throws Exception { // TODO Auto-generated method stub //ChannelPipeline 可以理解為訊息傳送通道 通道一旦建立 持續存在 ChannelPipeline channelPipeline = arg0.pipeline(); //為通道添加功能 //字串解碼 編碼 channelPipeline.addLast("decoder",new StringDecoder()); channelPipeline.addLast("encoder", new StringEncoder()); //添加自主邏輯 channelPipeline.addLast(new HelloServerHandler()); }}
3.HelloServerHandler
package com.nettypro.io;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.Scanner;import javax.xml.crypto.Data;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;public class HelloServerHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext arg0, String arg1) { // TODO Auto-generated method stub System.out.println(arg0.channel().remoteAddress()+" ----channelRead0"); //收到訊息直接列印 System.out.println(arg0.channel().remoteAddress()+" MSG: "+ arg1); //回複訊息 Scanner scanner = new Scanner(System.in); String msgString = scanner.nextLine()+"\n"; System.out.println(arg0.channel().remoteAddress()+" msgString: "+ msgString); arg0.writeAndFlush(msgString); } /** * channel被啟用時調用 */ @Override public void channelActive(ChannelHandlerContext ctx){ // TODO Auto-generated method stub System.out.println(ctx.channel().remoteAddress()+" ----Acrive"); try { ctx.writeAndFlush("Welcome you to here"+InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException e) { e.printStackTrace(); } }}
第三步:用戶端的建立:
#import "ViewController.h"#import <sys/socket.h>#import <netinet/in.h>#import <arpa/inet.h>#import <unistd.h>#import "AsyncSocket.h"@interface ViewController ()<AsyncSocketDelegate>@property (nonatomic, retain) NSTimer *heartTimer;@property (nonatomic, retain) AsyncSocket *ay;@property (strong, nonatomic) IBOutlet UITextField *msgTF;@property (strong, nonatomic) IBOutlet UITextView *showTV;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.ay = [[AsyncSocket alloc] initWithDelegate:self]; [self.ay connectToHost:@"localhost" onPort:8080 error:nil]; self.ay.delegate = self; NSString *msg = @"HelloNetty"; [self.ay writeData:[msg dataUsingEncoding:NSUTF8StringEncoding] withTimeout:10.0f tag:101]; [self.ay readDataWithTimeout:-1 tag:0];}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}- (IBAction)sendAction:(UIButton *)sender { if (self.msgTF.text.length != 0) { self.showTV.text = [NSString stringWithFormat:@"%@\n用戶端說:%@",self.showTV.text,self.msgTF.text]; [self.ay writeData:[self.msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:10.0f tag:101]; [self.ay readDataWithTimeout:-1 tag:0]; self.msgTF.text = nil; }}#pragma mark#pragma mark --AsyncSocketDelegate--- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"msg-----%@",msg); if (self.showTV.text.length == 0) { self.showTV.text = [NSString stringWithFormat:@"伺服器說:%@",msg]; } else { self.showTV.text = [NSString stringWithFormat:@"%@\n伺服器說:%@",self.showTV.text,msg]; } [self.ay readDataWithTimeout:-1 tag:0]; }- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ [self.ay readDataWithTimeout:-1 tag:0];}-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"didConnectToHost %@------%d",host,port); [self.ay readDataWithTimeout:-1 tag:0];}-(void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag{ NSLog(@"Received bytes: %lu",(unsigned long)partialLength);}@end