asyncsocket ios
2013-01-16 08:03:00 iteye_7514 阅读数 7

先分享下

NSLog(@"model -- %@",[UIDevice currentDevice].model);//判断是iphone或是ipad等

NSLog(@"version -- %@",[UIDevice currentDevice].systemVersion);//系统版本


下面的就是把头文件里的东西搬了出来

- (id)init;
- (id)initWithDelegate:(id)delegate;


/**
* Tells the socket to begin listening and accepting connections on the given port.
* When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above).
* The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)
**/
- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr;

在指定的端口侦听


/**
* Connects to the given host and port.
* The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2")
**/
- (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr;

向指定的host和端口连接,host格式可以是www.baidu.com 或者 192.168.100.100,它的timeout为-1.


/**
* This method is the same as connectToHost:onPort:error: with an additional timeout option.
* To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method.
**/
- (BOOL)connectToHost:(NSString *)hostname
onPort:(UInt16)port
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr;

和connectToHost:onPort:error: 差不多,就是加了个连接时间限制


/**
* Connects to the given address, specified as a sockaddr structure wrapped in a NSData object.
* For example, a NSData object returned from NSNetservice's addresses method.
*
* If you have an existing struct sockaddr you can convert it to a NSData object like so:
* struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
* struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;

这个把sockaddr封装到data中,sockaddr中有地址和端口,一直没有用过这个


/**
* This method is the same as connectToAddress:error: with an additional timeout option.
* To not time out use a negative time interval, or simply use the connectToAddress:error: method.
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;


/**
* Disconnects immediately. Any pending reads or writes are dropped.
* If the socket is not already disconnected, the onSocketDidDisconnect delegate method
* will be called immediately, before this method returns.
*
* Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method)
* [asyncSocket setDelegate:nil];
* [asyncSocket disconnect];
* [asyncSocket release];
**/

- (void)disconnect;

立即断开连接



/**
* Disconnects after all pending reads have completed.
* After calling this, the read and write methods will do nothing.
* The socket will disconnect even if there are still pending writes.
**/

- (void)disconnectAfterReading;



/**
* Disconnects after all pending writes have completed.
* After calling this, the read and write methods will do nothing.
* The socket will disconnect even if there are still pending reads.
**/
- (void)disconnectAfterWriting;



/**
* Disconnects after all pending reads and writes have completed.
* After calling this, the read and write methods will do nothing.
**/
- (void)disconnectAfterReadingAndWriting;


/**
* Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected.
* The host will be an IP address.
**/
- (NSString *)connectedHost;
- (UInt16)connectedPort;

- (NSString *)localHost;
- (UInt16)localPort;



/**
* Returns the local or remote address to which this socket is connected,
* specified as a sockaddr structure wrapped in a NSData object.
*
* See also the connectedHost, connectedPort, localHost and localPort methods.
**/
- (NSData *)connectedAddress;
- (NSData *)localAddress;


///////////////////// delegate////////////////////



/**
* In the event of an error, the socket is closed.
* You may call "unreadData" during this call-back to get the last bit of data off the socket.
* When connecting, this delegate method may be called
* before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:".
**/
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;



/**
* Called when a socket disconnects with or without error. If you want to release a socket after it disconnects,
* do so here. It is not safe to do that during "onSocket:willDisconnectWithError:".
*
* If you call the disconnect method, and the socket wasn't already disconnected,
* this delegate method will be called before the disconnect method returns.
**/
- (void)onSocketDidDisconnect:(AsyncSocket *)sock;



/**
* Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have
* the same delegate and will call "onSocket:didConnectToHost:port:".
**/
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;



/**
* Called when a new socket is spawned to handle a connection. This method should return the run-loop of the
* thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used.
**/
- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket;



/**
* Called when a socket is about to connect. This method should return YES to continue, or NO to abort.
* If aborted, will result in AsyncSocketCanceledError.
*
* If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the
* CFReadStream and CFWriteStream as desired prior to connection.
*
* If the connectToAddress:error: method was called, the delegate will be able to access and configure the
* CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and
* configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method.
**/
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock;



/**
* Called when a socket connects and is ready for reading and writing.
* The host parameter will be an IP address, not a DNS name.
**/
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;



/**
* Called when a socket has completed reading the requested data into memory.
* Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;



/**
* Called when a socket has read in data, but has not yet completed the read.
* This would occur if using readToData: or readToLength: methods.
* It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(CFIndex)partialLength tag:(long)tag;



/**
* Called when a socket has completed writing the requested data. Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;


/**
* Called when a socket has written some data, but has not yet completed the entire write.
* It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(CFIndex)partialLength tag:(long)tag;



/**
* Called if a read operation has reached its timeout without completing.
* This method allows you to optionally extend the timeout.
* If you return a positive time interval (> 0) the read's timeout will be extended by the given amount.
* If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual.
*
* The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
* The length parameter is the number of bytes that have been read so far for the read operation.
*
* Note that this method may be called multiple times for a single read if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(CFIndex)length;



/**
* Called if a write operation has reached its timeout without completing.
* This method allows you to optionally extend the timeout.
* If you return a positive time interval (> 0) the write's timeout will be extended by the given amount.
* If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual.
*
* The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
* The length parameter is the number of bytes that have been written so far for the write operation.
*
* Note that this method may be called multiple times for a single write if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
shouldTimeoutWriteWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(CFIndex)length;



/**
* Called after the socket has successfully completed SSL/TLS negotiation.
* This method is not called unless you use the provided startTLS method.
*
* If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close,
* and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code.
**/
- (void)onSocketDidSecure:(AsyncSocket *)sock;


//////////////////// 例子/////////////////


初始化

socket=[[AsyncSocket alloc]initWithDelegate:self];
[socket acceptOnPort:3000 error:nil];
connectedSockets=[[NSMutableArray alloc]initWithCapacity:1];

代理

-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
[connectedSockets addObject:newSocket];

}
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
// NSLog(@"peer host -> %@",[sock connectedAddress]);
NSString *welcomeMsg = @"hello message";
NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:welcomeData withTimeout:-1 tag:1000];
[sock readDataWithTimeout:1000 tag:2000];
}
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSLog(@"read data");
NSLog(@" string ->> %@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding] );
}

-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"write data");
}


2014-03-19 15:40:47 bluewindaa 阅读数 801

iOS中的socket通信,用到了AsyncSocket开源的框架,不错,挺好用的。先贴代码。

OC: (Client)

-(void)connectButtonPressed {

 

   

   if (!asyncSocket){

       

      asyncSocket =[[AsyncSocket allocinitWithDelegate:self];

      NSError *err= nil;

       

      if(![asyncSocket connectToHost:@"192.168.1.103" onPort:25001withTimeout:10 error:&err]){

          

          NSLog(@"Error:%@", err);

          

      }

   }

   

}



- (void)sendButtonPressed {

   


   NSData*aData= [inputTextView.text dataUsingEncodingNSUTF8StringEncoding];

   

   [asyncSocket writeData:aData withTimeout:-1 tag:1];

   

}


-(void)ontime{

   

   [asyncSocket readDataWithTimeout:-1 tag:0];

   

}



- (void)onSocket:(AsyncSocket *)sockdidConnectToHost:(NSString *)hostport:(UInt16)port

{

   NSLog(@"onSocket:%pdidConnectToHost:%@ port:%hu", sock, host,port);

   

   //Add timer.

   timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:selfselector:@selector(ontime) userInfo:nil repeats:YES];

}


-(void)onSocket:(AsyncSocket *)sockdidReadData:(NSData *)datawithTag:(long)tag

{

   NSString*aStr = [[NSString allocinitWithData:dataencoding:NSUTF8StringEncoding];

   messageTextView.text =[NSString stringWithFormat:@"%@\n Server: %@",messageTextView.text,aStr];;

   

   [aStr release];


}


- (void)onSocket:(AsyncSocket *)sockdidSecure:(BOOL)flag

{

   NSLog(@"onSocket:%pdidSecure:YES",sock);

}


- (void)onSocket:(AsyncSocket *)sockwillDisconnectWithError:(NSError *)err

{

   NSLog(@"onSocket:%pwillDisconnectWithError:%@", sock,err);

   

   [timer invalidate];

   timer nil;

   

}


- (void)onSocketDidDisconnect:(AsyncSocket *)sock

{

   //断开连接了

   NSLog(@"onSocketDidDisconnect:%p",sock);

}


-(void)onSocket:(AsyncSocket *)sockdidWriteDataWithTag:(long)tag


{

   

   NSLog(@"thread(%@),onSocket:%pdidWriteDataWithTag:%ld",[[NSThreadcurrentThreadname],sock,tag);


}


C#: (Server) 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;


namespace SocketServer
{
    publicpartial class Form1 : Form
    {

       private IPAddress clientIP =IPAddress.Parse("192.168.1.103");//以本机作测试
       private IPEndPoint serverfulladdr;//完整终端地址
       private Socket sock;
       private System.Timers.Timer mytimer;
       private ArrayList alsock;//当建立了多个连接时用于保存连接


       public Form1()
       {
           InitializeComponent();
       }

       private void btstart_Click(object sender, EventArgs e)
       {

           serverfulladdr = new IPEndPoint(clientIP, 25001);//取端口号1000

           //构造socket对象,套接字类型为“流套接字”,指定五元组中的协议元

           sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

           //指定五元组中的本地二元,即本地主机地址和端口号

           sock.Bind(serverfulladdr);

           //监听是否有连接传入,指定挂起的连接队列的最大值为20

           sock.Listen(20);

           alsock = new ArrayList();

           //构造定时器,时间间隙为1秒,即每隔一秒执行一次accept()方法,以获取连接请求队列中//第一个挂起的连接请求
           mytimer = new System.Timers.Timer(1000);

           mytimer.Elapsed += newSystem.Timers.ElapsedEventHandler(mytimer_elapsed);

           mytimer.Enabled = true;

       }

 

       private void mytimer_elapsed(object sender,System.Timers.ElapsedEventArgs e)
       {

           mytimer.Enabled = false;

           //执行accept(),当挂起队列为空时将阻塞本线程,同时由于上一语句,定时器将停止,直//至有连接传入

           Socket acceptsock = sock.Accept();

           //将accept()产生的socket对象存入arraylist

           alsock.Add(acceptsock);

           //构造threading.timer对象,这将导致程序另启线程。线程将执行回调函数,该委托限制//函数参数须为object型。threading.timer构造器的第二个参数即传入回调函数的参数;第//三个参数指定调用回调函数之前的延时,取0则立即启动;最后一个参数指定调用回调函数//的时间间隔,取0则只执行一次。

           System.Threading.Timer ti = new System.Threading.Timer(newSystem.Threading.TimerCallback(receivemsg), acceptsock, 0, 0);

           mytimer.Enabled = true;

       }

 

       private void receivemsg(object obj)
       {

           Socket acceptsock = (Socket)obj;

           try
           {

               while (true)
               {

                   byte[] bytearray = new byte[100];

                   acceptsock.Receive(bytearray);//接收数据

                   //将字节数组转成字符串

                   string strrec = System.Text.Encoding.UTF8.GetString(bytearray);

                   if (this.rtbreceive.InvokeRequired)
                   {

                       this.rtbreceive.Invoke(new EventHandler(this.changericktextbox),new object[] { strrec, EventArgs.Empty });

                   }

               }

           }

           catch (Exception ex)
           {

               acceptsock.Close();

               MessageBox.Show("s:receive message error" + ex.Message);

           }

       }

 

       private void changericktextbox(object obj, EventArgs e)
       {

           string s = System.Convert.ToString(obj);

           this.rtbreceive.AppendText(s + Environment.NewLine);

       }


       private void btsend_Click(object sender, EventArgs e)
       {

           Socket sc = null;

           byte[] bytesend =System.Text.Encoding.UTF8.GetBytes(this.txtinput.Text.ToCharArray());

           try
           {

               //同时存在若干个客户端连接时,需要确定是哪个连接,因为我的调试都是一个连接,所以直接用0

               sc = (Socket)alsock[0];

               //发送数据

               sc.Send(bytesend);

           }

           catch (Exception ex)
           {

               if (sc != null)
               {
                   sc.Close();
               }

               MessageBox.Show("s:send message error" + ex.Message);
           }
       }


       private void btclose_Click(object sender, EventArgs e)
       {

           try
           {
               Application.Exit();
           }

           catch (Exception ex)
           {
               MessageBox.Show("s:close socket error" + ex.Message);
           }

       }

    }
}

仅限局域网络

2013-01-16 16:03:51 MyGameZone 阅读数 8176

    先分享下

    NSLog(@"model -- %@",[UIDevice currentDevice].model);//判断是iphone或是ipad等

    NSLog(@"version -- %@",[UIDevice currentDevice].systemVersion);//系统版本


  下面的就是把头文件里的东西搬了出来

- (id)init;
- (id)initWithDelegate:(id)delegate;


/**
 * Tells the socket to begin listening and accepting connections on the given port.
 * When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above).
 * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)
**/
- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr;

在指定的端口侦听


/**
 * Connects to the given host and port.
 * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2")
**/
- (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr;

向指定的host和端口连接,host格式可以是www.baidu.com 或者 192.168.100.100,它的timeout为-1.


/**
 * This method is the same as connectToHost:onPort:error: with an additional timeout option.
 * To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method.
**/
- (BOOL)connectToHost:(NSString *)hostname
               onPort:(UInt16)port
          withTimeout:(NSTimeInterval)timeout
                error:(NSError **)errPtr;

和connectToHost:onPort:error: 差不多,就是加了个连接时间限制


/**
 * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object.
 * For example, a NSData object returned from NSNetservice's addresses method.
 *
 * If you have an existing struct sockaddr you can convert it to a NSData object like so:
 * struct sockaddr sa  -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
 * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;

这个把sockaddr封装到data中,sockaddr中有地址和端口,一直没有用过这个


/**
 * This method is the same as connectToAddress:error: with an additional timeout option.
 * To not time out use a negative time interval, or simply use the connectToAddress:error: method.
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;


/**
 * Disconnects immediately. Any pending reads or writes are dropped.
 * If the socket is not already disconnected, the onSocketDidDisconnect delegate method
 * will be called immediately, before this method returns.
 *
 * Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method)
 * [asyncSocket setDelegate:nil];
 * [asyncSocket disconnect];
 * [asyncSocket release];
**/

- (void)disconnect;

立即断开连接



/**
 * Disconnects after all pending reads have completed.
 * After calling this, the read and write methods will do nothing.
 * The socket will disconnect even if there are still pending writes.
**/

- (void)disconnectAfterReading;



/**
 * Disconnects after all pending writes have completed.
 * After calling this, the read and write methods will do nothing.
 * The socket will disconnect even if there are still pending reads.
**/
- (void)disconnectAfterWriting;



/**
 * Disconnects after all pending reads and writes have completed.
 * After calling this, the read and write methods will do nothing.
**/
- (void)disconnectAfterReadingAndWriting;


/**
 * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected.
 * The host will be an IP address.
**/
- (NSString *)connectedHost;
- (UInt16)connectedPort;

- (NSString *)localHost;
- (UInt16)localPort;



/**
 * Returns the local or remote address to which this socket is connected,
 * specified as a sockaddr structure wrapped in a NSData object.
 *
 * See also the connectedHost, connectedPort, localHost and localPort methods.
**/
- (NSData *)connectedAddress;
- (NSData *)localAddress;


/////////////////////  delegate////////////////////



/**
 * In the event of an error, the socket is closed.
 * You may call "unreadData" during this call-back to get the last bit of data off the socket.
 * When connecting, this delegate method may be called
 * before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:".
**/
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;



/**
 * Called when a socket disconnects with or without error.  If you want to release a socket after it disconnects,
 * do so here. It is not safe to do that during "onSocket:willDisconnectWithError:".
 *
 * If you call the disconnect method, and the socket wasn't already disconnected,
 * this delegate method will be called before the disconnect method returns.
**/
- (void)onSocketDidDisconnect:(AsyncSocket *)sock;



/**
 * Called when a socket accepts a connection.  Another socket is spawned to handle it. The new socket will have
 * the same delegate and will call "onSocket:didConnectToHost:port:".
**/
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;



/**
 * Called when a new socket is spawned to handle a connection.  This method should return the run-loop of the
 * thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used.
**/
- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket;



/**
 * Called when a socket is about to connect. This method should return YES to continue, or NO to abort.
 * If aborted, will result in AsyncSocketCanceledError.
 *
 * If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the
 * CFReadStream and CFWriteStream as desired prior to connection.
 *
 * If the connectToAddress:error: method was called, the delegate will be able to access and configure the
 * CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and
 * configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method.
**/
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock;



/**
 * Called when a socket connects and is ready for reading and writing.
 * The host parameter will be an IP address, not a DNS name.
**/
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;



/**
 * Called when a socket has completed reading the requested data into memory.
 * Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;



/**
 * Called when a socket has read in data, but has not yet completed the read.
 * This would occur if using readToData: or readToLength: methods.
 * It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(CFIndex)partialLength tag:(long)tag;



/**
 * Called when a socket has completed writing the requested data. Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;


/**
 * Called when a socket has written some data, but has not yet completed the entire write.
 * It may be used to for things such as updating progress bars.
**/
- (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(CFIndex)partialLength tag:(long)tag;



/**
 * Called if a read operation has reached its timeout without completing.
 * This method allows you to optionally extend the timeout.
 * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount.
 * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual.
 *
 * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
 * The length parameter is the number of bytes that have been read so far for the read operation.
 *
 * Note that this method may be called multiple times for a single read if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
  shouldTimeoutReadWithTag:(long)tag
                   elapsed:(NSTimeInterval)elapsed
                 bytesDone:(CFIndex)length;



/**
 * Called if a write operation has reached its timeout without completing.
 * This method allows you to optionally extend the timeout.
 * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount.
 * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual.
 *
 * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.
 * The length parameter is the number of bytes that have been written so far for the write operation.
 *
 * Note that this method may be called multiple times for a single write if you return positive numbers.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
 shouldTimeoutWriteWithTag:(long)tag
                   elapsed:(NSTimeInterval)elapsed
                 bytesDone:(CFIndex)length;



/**
 * Called after the socket has successfully completed SSL/TLS negotiation.
 * This method is not called unless you use the provided startTLS method.
 *
 * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close,
 * and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code.
**/
- (void)onSocketDidSecure:(AsyncSocket *)sock;


//////////////////// 例子/////////////////


初始化

    socket=[[AsyncSocket alloc]initWithDelegate:self];
    [socket acceptOnPort:3000 error:nil];
    connectedSockets=[[NSMutableArray alloc]initWithCapacity:1];

代理

-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
    [connectedSockets addObject:newSocket];
    
}
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
   // NSLog(@"peer host -> %@",[sock connectedAddress]);
    NSString *welcomeMsg = @"hello message";
    NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding];
    [sock writeData:welcomeData withTimeout:-1 tag:1000];
    [sock readDataWithTimeout:1000 tag:2000];
}
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSLog(@"read data");
    NSLog(@" string ->> %@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding] );
}

-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    NSLog(@"write data");
}


2016-09-06 14:46:00 weixin_33958585 阅读数 34
  • 使用AsyncSocket的时候可以做一层封装,根据需求提供几个接口出来。比如:连接、断开连接、发送消息等等。还有接受消息,接受到的消息可以通过通知、代理、block等传出去。
  • 对AsyncSocket使用.一般来说,一个用户只需要建立一个socket长连接,所以可以用单例类方便使用。
使用AsyncSocket

1.创建socket的单例类

//在LGSocketServe.h 
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
#import "GCDAsyncSocket.h"
@interface LGSocketServe : NSObject
//创建属性 用于连接
@property (nonatomic, strong, readonly) GCDAsyncSocket          *socket;
@property (nonatomic, copy,   readonly) NSString                *socketHost;
@property (nonatomic, assign, readonly) uint16_t                socketPort;

//创建单列类
+(instancetype)shareSocket;
@end



//在LGSocketServe.m
#import "LGSocketServe.h"
#import <UIKit/UIKit.h>

@interface LGSocketServe ()

@property (nonatomic, strong, readwrite) GCDAsyncSocket         *socket;
@property (nonatomic, copy,   readwrite) NSString               *socketHost;
@property (nonatomic, assign, readwrite) uint16_t               socketPort;

@end

@implementation LGSocketServe 

+(instancetype)shareSocket
{
    static dispatch_once_t onceToken;
    static LGSocketServe *socket;
    dispatch_once(&onceToken, ^{
        socket = [[LGSocketServe alloc]init];
    });
    return socket;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    }
    return self;
}
//创建连接
- (void)connected:(NSString *)host onPort:(uint16_t)port error:(NSError *)error{
    self.socketHost = host;
    self.socketPort = port;
    //必须确认在断开连接的情况下,进行连接
    if (self.socket.isDisconnected) {
        [self.socket connectToHost:self.socketHost onPort:self.socketPort error:nil];
    }else{
        [self.socket disconnect];
        [self.socket connectToHost:self.socketHost onPort:self.socketPort error:nil];
    }
    [self.socket connectToHost:host onPort:port error:nil];
}
//心跳连接
-(void)longConnectToSocket{
    // 根据服务器要求发送固定格式的数据,假设为指令@"longConnect",但是一般不会是这么简单的指令
    NSString *longConnect = @"longConnect\r\n";
    NSData   *dataStream  = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
    [self.socket writeData:dataStream withTimeout:-1 tag:0];
}
//连接成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    //每隔特定时间向服务器发送心跳包
    //在longConnectToSocket方法中进行长连接需要向服务器发送特定信息
    self.longConnectTimer
    = [NSTimer timerWithTimeInterval:kSocketConnectTimerTimeInterval
                              target:self
                            selector:@selector(longConnectToSocket)
                            userInfo:nil
                             repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.longConnectTimer
                                 forMode:NSRunLoopCommonModes];
}
//断开连接
- (void)disConnected{

    [self.socket disconnect];
}
//断开之后重新连接
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    //这里可以列举枚举值
    //因用户自动断开 不自动连接
    if (self.offlineError == SZYSocketOfflineByServer) {
        [self.longConnectTimer invalidate];
        self.longConnectTimer = nil;
        [self.socket setDelegate:nil];
        [self.socket disconnect];
    //因服务器原因断开 自动连接
    }else if (self.offlineError == SZYSocketOfflineByServer){
    
        [self.longConnectTimer invalidate];
        self.longConnectTimer = nil;
        [self.socket setDelegate:nil];
        [self.socket disconnect];
        [self.socket setDelegate:self];
        [self.socket connectToHost:self.socketHost
                            onPort:self.socketPort
                             error:nil];
    //因Wifi原因断开 不自动连接
    }else{
        [self.longConnectTimer invalidate];
        self.longConnectTimer = nil;
        [self.socket setDelegate:nil];
        [self.socket disconnect];
    }
    
}
//写入数据
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag{

    [self.socket writeData:data withTimeout:-1 tag:100];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"读取到的消息:%@", dataString);
}
//读取数据
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag{
    [self.socket readDataToData:data withTimeout:-1 tag:100];
    
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSLog(@"didWriteDataWithTag");
}

有错误欢迎留言指正

2016-08-14 22:20:00 weixin_33836223 阅读数 2

1、AsyncSocket

  • 基于 CFSocket、GCD 进行的封装(OC)。

  • 支持 TCP 和 UDP。

  • 完整的回调函数(用于处理各种回调事件,连接成功,断开连接,收到数据等)。

  • 需要注意的问题:

    • 1、Socekt 连接成功回调方法中主动调用:[self.socket readDataWithTimeout:-1 tag:0];,相当于主动添加一个读取请求,不然不会执行读取信息回调方法。
    • 2、读取信息回调方法中,读取完信息后,主动调用一下 [self.socket readDataWithTimeout:-1 tag:0];,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。

2、基本使用

2.1 Client 客户端

  • TCP 客户端

        #import "GCDAsyncSocket.h"
    
        @interface ViewController () <GCDAsyncSocketDelegate>
    
        @property (weak, nonatomic) IBOutlet UITextField *addrTF;
        @property (weak, nonatomic) IBOutlet UITextField *portTF;
    
        @property (weak, nonatomic) IBOutlet UITextField *msgTF;
        @property (weak, nonatomic) IBOutlet UITextView *logTV;
    
        @property (nonatomic, strong) GCDAsyncSocket *clientSockfd;
    
        @end
    
        @implementation ViewController
    
        - (void)viewDidLoad {
            [super viewDidLoad];
    
            // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行。
            self.clientSockfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        }
    
        - (IBAction)connectBtnClick:(id)sender {
    
            NSError *error = nil;
    
            // Socket 连接
            if (![self.clientSockfd isConnected]) {
                [self.clientSockfd connectToHost:_addrTF.text onPort:_portTF.text.intValue error:&error];
            }
    
            if (error != nil) {
                [self showLogMessage:@"连接失败..."];
            }
        }
    
        #pragma mark - GCDAsyncSocketDelegate 协议方法
    
        // 连接成功,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    
            // 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法
            [self.clientSockfd readDataWithTimeout:-1 tag:0];
    
            [self showLogMessage:[NSString stringWithFormat:@"连接服务器地址:%@, 端口:%d 成功", host, port]];
            [self showLogMessage:[NSString stringWithFormat:@"本地地址:%@, 端口:%d", sock.localHost, sock.localPort]];
        }
    
        // 已经断开链接,协议方法
        - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    
            [self showLogMessage:@"socket 断开连接..."];
        }
    
        // 读取到数据,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
            // 注意:要想长连接,必须还要在 DidReceiveData 的 delegate 中再写一次 [_udpSocket receiveOnce:&error]
    
            // 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。
            [self.clientSockfd readDataWithTimeout:-1 tag:0];
    
            NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            [self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];
        }
    
        #pragma mark - 发送数据
    
        - (IBAction)sendBtnClick:(id)sender {
    
            // Socket 发送数据
            [self.clientSockfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];
    
            [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
        }
    
        // 显示信息
        - (void)showLogMessage:(NSString *)msg {
    
            _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
        }
    
        // 键盘回收
        - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
            [self.view endEditing:YES];
        }
    
        @end

    Socket11

2.2 Server 服务端

  • TCP 服务端

        #import <arpa/inet.h>
        #import <ifaddrs.h>
    
        #import "GCDAsyncSocket.h"
    
        @interface ViewController () <GCDAsyncSocketDelegate>
    
        @property (weak, nonatomic) IBOutlet UITextField *addrTF;
        @property (weak, nonatomic) IBOutlet UITextField *portTF;
    
        @property (weak, nonatomic) IBOutlet UITextField *msgTF;
        @property (weak, nonatomic) IBOutlet UITextView *logTV;
    
        @property (nonatomic, strong) GCDAsyncSocket *serverSocketfd;
        @property (nonatomic, strong) GCDAsyncSocket *clientSocketfd;
    
        @end
    
        @implementation ViewController
    
        - (void)viewDidLoad {
            [super viewDidLoad];
    
            NSString *ip_addr = [self getIPAddress];
            _addrTF.text = ip_addr;
    
            // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行。
            self.serverSocketfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        }
    
        - (IBAction)listenBtnClick:(id)sender {
    
            NSError *error = nil;
    
            // Socket 监听
            [self.serverSocketfd acceptOnPort:_portTF.text.intValue error:&error];
    
            if (error != nil) {
                NSLog(@"监听出错:%@", error);
            } else{
                [self showLogMessage:@"正在监听..."];
            }
        }
    
        #pragma mark - GCDAsyncSocketDelegate 协议方法
    
        // 接收到连接请求,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
    
            // 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法
            [newSocket readDataWithTimeout:-1 tag:0];
    
            [self showLogMessage:@"收到客户端连接...."];
            [self showLogMessage:[NSString stringWithFormat:@"客户端地址:%@, 端口:%d", newSocket.connectedHost, newSocket.connectedPort]];
    
            self.clientSocketfd = newSocket;
        }
    
        // 已经断开链接,协议方法
        - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    
            [self showLogMessage:@"socket 断开连接..."];
        }
    
        // 读取到数据,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
            // 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。
            [sock readDataWithTimeout:-1 tag:0];
    
            NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            [self showLogMessage:[NSString stringWithFormat:@"recv:%@",strMsg]];
        }
    
        #pragma mark - 发送数据
    
        - (IBAction)sendBtnClick:(id)sender {
    
            // Socket 发送数据
            [self.clientSocketfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];
    
            [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
        }
    
        #pragma mark - 获取本地 IP 地址
    
        - (NSString *)getIPAddress {
    
            NSString *address = @"error";
            struct ifaddrs *interfaces = NULL;
            struct ifaddrs *temp_addr = NULL;
            int success = 0;
    
            // retrieve the current interfaces - returns 0 on success
            success = getifaddrs(&interfaces);
    
            if (success == 0) {
    
                // Loop through linked list of interfaces
                temp_addr = interfaces;
    
                while (temp_addr != NULL) {
    
                    if (temp_addr->ifa_addr->sa_family == AF_INET) {
    
                        // Check if interface is en0 which is the wifi connection on the iPhone
                        if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
    
                            // Get NSString from C String
                            address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                        }
                    }
                    temp_addr = temp_addr->ifa_next;
                }
            }
    
            // Free memory
            freeifaddrs(interfaces);
            return address;
        }
    
        // 显示信息
        - (void)showLogMessage:(NSString *)msg {
    
            _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
        }
    
        // 键盘回收
        - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
            [self.view endEditing:YES];
        }
    
        @end

    Socket12

2.3 UDP 通信

  • UDP 通信

        #import <arpa/inet.h>
        #import <ifaddrs.h>
    
        #import "GCDAsyncUdpSocket.h"
    
        @interface ViewController () <GCDAsyncUdpSocketDelegate>
    
        @property (weak, nonatomic) IBOutlet UITextField *desAddrTF;
        @property (weak, nonatomic) IBOutlet UITextField *desPortTF;
    
        @property (weak, nonatomic) IBOutlet UITextField *locAddrTF;
        @property (weak, nonatomic) IBOutlet UITextField *locPortTF;
    
        @property (weak, nonatomic) IBOutlet UITextField *msgTF;
        @property (weak, nonatomic) IBOutlet UITextView *logTV;
    
        @property (nonatomic, strong) GCDAsyncUdpSocket *udpSocketfd;
    
        @end
    
        @implementation ViewController
    
        - (void)viewDidLoad {
            [super viewDidLoad];
    
            NSString *ip_addr = [self getIPAddress];
            _locAddrTF.text = ip_addr;
    
            // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行
            self.udpSocketfd = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        }
    
        - (IBAction)connectBtnClick:(id)sender {
    
            NSError *error = nil;
    
            // 绑定端口
            [self.udpSocketfd bindToPort:_locPortTF.text.intValue error:&error];
    
            if (error != nil) {
                NSLog(@"绑定端口出错:%@", error);
                return;
            } else{
                [self showLogMessage:[NSString stringWithFormat:@"绑定端口 %d 成功...", _locPortTF.text.intValue]];
            }
    
            // 开始接收数据
            [self.udpSocketfd beginReceiving:&error];
    
            if (error != nil) {
                NSLog(@"开始接收数据出错:%@", error);
            } else{
                [self showLogMessage:@"开始接收数据..."];
            }
        }
    
        #pragma mark - GCDAsyncUdpSocketDelegate 协议方法
    
        // 接收到的数据,协议方法
        - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
                                                       fromAddress:(NSData *)address
                                                 withFilterContext:(id)filterContext {
    
            NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
            [self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];
        }
    
        #pragma mark - 发送数据
    
        - (IBAction)sendBtnClick:(id)sender {
    
            // Socket 发送数据
            [self.udpSocketfd sendData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]
                                toHost:_desAddrTF.text
                                  port:_desPortTF.text.intValue
                           withTimeout:30 tag:0];
    
            [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
        }
    
        #pragma mark - 获取本地 IP 地址
    
        - (NSString *)getIPAddress {
    
            NSString *address = @"error";
            struct ifaddrs *interfaces = NULL;
            struct ifaddrs *temp_addr = NULL;
            int success = 0;
    
            // retrieve the current interfaces - returns 0 on success
            success = getifaddrs(&interfaces);
    
            if (success == 0) {
    
                // Loop through linked list of interfaces
                temp_addr = interfaces;
    
                while (temp_addr != NULL) {
    
                    if (temp_addr->ifa_addr->sa_family == AF_INET) {
    
                        // Check if interface is en0 which is the wifi connection on the iPhone
                        if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
    
                            // Get NSString from C String
                            address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                        }
                    }
                    temp_addr = temp_addr->ifa_next;
                }
            }
    
            // Free memory
            freeifaddrs(interfaces);
            return address;
        }
    
        // 显示信息
        - (void)showLogMessage:(NSString *)msg {
    
            _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
        }
    
        // 键盘回收
        - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
            [self.view endEditing:YES];
        }
    
        @end

    Socket13

2.4 Socket 长连接

  • PublicTool.h

        @interface PublicTool : NSObject
    
        // 字典转换成 JSON 字符串
        + (NSString *)JSONStringWithDic:(NSDictionary *)dic;
    
        // JSON 字符串转换成字典
        + (NSDictionary *)dictionaryWithJSON:(NSString *)json;
    
        @end
  • PublicTool.m

        @implementation PublicTool
    
        // 字典转成成 JSON 字符串
        + (NSString *)JSONStringWithDic:(NSDictionary *)dic {
    
            NSError *error = nil;
    
            NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic
                                                               options:0
                                                                 error:&error];
    
            if (jsonData == nil) {
                NSLog(@"fail to get JSON from dictionary: %@, error: %@", self, error);
    
                return nil;
            }
            NSString *jsonString = [[NSString alloc] initWithData:jsonData
                                                         encoding:NSUTF8StringEncoding];
    
            return jsonString;
        }
    
        // JSON 字符串转换成字典
        + (NSDictionary *)dictionaryWithJSON:(NSString *)json {
    
            NSError *error = nil;
    
            NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
    
            NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                                     options:NSJSONReadingMutableContainers |
                                                                             NSJSONReadingAllowFragments
                                                                       error:&error];
    
            if (jsonDict == nil) {
                NSLog(@"fail to get dictioanry from JSON: %@, error: %@", json, error);
    
                return nil;
            }
    
            return jsonDict;
        }
    
        @end
  • SocketSingleTon.h

        @interface SocketSingleTon : NSObject
    
        @property (nonatomic, copy) NSString *hostAddr;
        @property (nonatomic, copy) NSString *port;
    
        @property (nonatomic, copy) void(^msgLog)(NSString *);
    
        + (instancetype)shareInstance;
    
        // 连接到服务器
        - (void)connectToServer;
    
        // 断开连接
        - (void)cutOffSocket;
    
        // 发送数据到服务器
        - (void)sendDataToServer:(NSData*)data;
    
        @end
  • SocketSingleTon.m

        #import "GCDAsyncSocket.h"
        #import <netdb.h>
        #import <arpa/inet.h>
    
        #import "PublicTool.h"
    
        typedef NS_ENUM(NSInteger, SocketOffline) {
            SocketOfflineByServer,
            SocketOfflineByUser
        };
    
        @interface SocketSingleTon () <GCDAsyncSocketDelegate>
    
        @property (nonatomic, strong) GCDAsyncSocket *socket;
    
        @property (nonatomic, strong) NSTimer *beatTimer;
    
        @end
    
        @implementation SocketSingleTon
    
        + (instancetype)shareInstance {
    
            static SocketSingleTon *shareInstance = nil;
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                shareInstance = [[self alloc] init];
            });
            return shareInstance;
        }
    
        // 连接到服务器
        - (void)connectToServer {
    
            NSError *error = nil;
    
            if (self.socket != nil) {
    
                if ([self.socket isConnected]) {
    
                    // 断开后再连接
                    self.socket.userData = @(SocketOfflineByUser);
                    [self cutOffSocket];
    
                    [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];
    
                } else {
    
                    [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];
                }
    
            } else {
                self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    
                [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];
            }
    
            if (error != nil) {
                NSLog(@"socket 连接失败:%@", error);
            } else {
                NSLog(@"socket 连接成功");
            }
        }
    
        // 断开连接
        - (void)cutOffSocket {
    
            self.socket.userData = @(SocketOfflineByUser);
            [self.socket disconnect];
        }
    
        #pragma mark  - GCDAsyncSocketDelegate 协议方法
    
        // 连接成功,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    
            [sock readDataWithTimeout:-1 tag:0];
    
            NSString *logStr = [NSString stringWithFormat:@"连接主机:%@:%d 成功\n", host, port];
            NSLog(@"%@", logStr);
    
            if (self.msgLog) {
                self.msgLog(logStr);
            }
    
            // 创建定时器,定时发送 beat 包
            self.beatTimer = [NSTimer scheduledTimerWithTimeInterval:5 
                                                              target:self 
                                                            selector:@selector(longConnectToServer) 
                                                            userInfo:nil 
                                                             repeats:YES];
        }
    
        // 连接断开,协议方法
        - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    
            self.socket = nil;
    
            [self.beatTimer invalidate];
            self.beatTimer = nil;
    
            if ([sock.userData  isEqual: @(SocketOfflineByUser)]) {
    
                NSLog(@"the socket have been cutted off by user");
    
                if (self.msgLog) {
                    self.msgLog(@"the socket have been cutted off by user");
                }
    
            } else if (sock.userData == SocketOfflineByServer) {
    
                NSLog(@"the socket have been cutted off by server");
    
                if (self.msgLog) {
                    self.msgLog(@"the socket have been cutted off by server");
                }
    
                // reconnect
                [self connectToServer];
    
            } else {
    
                NSLog(@"%@", err.localizedDescription);
    
                if (self.msgLog) {
                    self.msgLog([NSString stringWithFormat:@"%@", err.localizedDescription]);
                }
    
                [self connectToServer];
            }
        }
    
        // 收到消息,协议方法
        - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
            [sock readDataWithTimeout:-1 tag:0];
    
            char buf[1024];
            [data getBytes:buf length:1024];
    
            NSString *receivedData = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
            NSLog(@"receivedData:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    
            if (receivedData.length > 0) {
    
                NSDictionary *dataDic = [PublicTool dictionaryWithJSON:receivedData];
    
                if ([dataDic[@"msgType"] isEqualToString:@"beta"]) {
                    NSString *strMsg = [NSString stringWithFormat:@"收到心跳确认的数据:%@\n", receivedData];
                    if (self.msgLog) {
                        self.msgLog(strMsg);
                    }
                } else if ([dataDic[@"msgType"] isEqualToString:@"normal"]) {
                    NSString *strMsg = [NSString stringWithFormat:@"收到正常的数据:%@\n", receivedData];
                    if (self.msgLog) {
                        self.msgLog(strMsg);
                    }
                } else if ([dataDic[@"msgType"] isEqualToString:@"exit"]) {
                    NSString *strMsg = [NSString stringWithFormat:@"收到关闭的数据:%@\n", receivedData];
                    if (self.msgLog) {
                        self.msgLog(strMsg);
                    }
                    [self cutOffSocket];
                }
            }
        }
    
        // 发送数据
        - (void)longConnectToServer {
            [self sendDataToServer:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        // 发送数据到服务器
        - (void)sendDataToServer:(NSData*)data {
    
            NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];
    
            if ([dataStr isEqualToString:@"hello"]) {
                [dicParams setValue:dataStr forKey:@"msg"];
                [dicParams setValue:@"beta" forKey:@"msgType"];
            } else {
                [dicParams setValue:dataStr forKey:@"msg"];
                [dicParams setValue:@"normal" forKey:@"msgType"];
            }
    
            NSData *sendData = [[PublicTool JSONStringWithDic:dicParams] dataUsingEncoding:NSUTF8StringEncoding];
    
            NSString *strMsg = [NSString stringWithFormat:@"发送数据: %@\n", [PublicTool JSONStringWithDic:dicParams]];
            if (self.msgLog) {
                self.msgLog(strMsg);
            }
    
            [self.socket writeData:sendData withTimeout:30 tag:0];
        }
    
        @end
  • ViewController.m

        #import "SocketSingleTon.h"
        #import "PublicTool.h"
    
        @interface ViewController ()
    
        @property (weak, nonatomic) IBOutlet UITextField *addressTF;
        @property (weak, nonatomic) IBOutlet UITextField *portTF;
    
        @property (weak, nonatomic) IBOutlet UITextField *msgTF;
        @property (weak, nonatomic) IBOutlet UITextView *logTV;
    
        @end
    
        @implementation ViewController
    
        - (IBAction)connectToServer:(id)sender {
    
            // 创建 Socket
            SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];
    
            socketInstance.hostAddr = _addressTF.text;
            socketInstance.port = _portTF.text;
    
            __weak __typeof (self)weakSelf = self;
            socketInstance.msgLog = ^(NSString *log){
    
                dispatch_async(dispatch_get_main_queue(), ^{
                    weakSelf.logTV.text = [weakSelf.logTV.text stringByAppendingString:log];
                });
            };
    
            // 连接到服务器
            [socketInstance connectToServer];
        }
    
        - (IBAction)cutOffConnect:(id)sender {
    
            SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];
    
            // 断开连接
            [socketInstance cutOffSocket];
        }
    
        - (IBAction)sendDataToServer:(id)sender {
    
            SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];
    
            // 发送数据到服务器
            [socketInstance sendDataToServer:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        - (IBAction)sendBetaDataToServer:(id)sender {
    
            SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];
    
            NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];
            [dicParams setValue:@"beta" forKey:@"msgType"];
            [dicParams setValue:@"hello" forKey:@"msg"];
            NSString *strMsg = [PublicTool JSONStringWithDic:dicParams];
    
            // 发送心跳数据到服务器
            [socketInstance sendDataToServer:[strMsg dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        - (IBAction)clearLog:(id)sender {
            _logTV.text = nil;
        }
    
        // 键盘回收
        - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
            [self.view endEditing:YES];
        }
    
        @end

    Socket14

没有更多推荐了,返回首页