文章目录
  1. 1. socket编程
    1. 1.1. CocoaAsyncSocket
    2. 1.2. AsyncSocket使用
      1. 1.2.1. 大概过程
      2. 1.2.2. 客户端-服务端
    3. 1.3. 关键代码

socket编程

CocoaAsyncSocket

AsyncSocket使用

大概过程

  • 1.建立连接
  • - (int)connectServer:(NSString *)hostIP port:(int)hostPort
  • 2.连接成功后,会回调的函数
  • - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
  • 3.发送数据
  • - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
  • 4.接受数据
  • - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
  • 5.断开连接
  • - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
  • - (void)onSocketDidDisconnect:(AsyncSocket *)sock

    客户端-服务端

  • 客户端呢,首先要由一个ip地址和端口,用这个来连接服务器。
    • 直接初始化socket(指定代理)
    • 连接服务器
    • 接收或者发送数据
    • 断开连接
  • 服务端呢
    • 初始化监听socket开始监听客户端连接,如果有客户端连接进来,就初始化连接socket,添加到socket数组
    • 然后开始收发数据(代理方法)
    • 关闭连接

关键代码

  • 客户端

#define SRV_CONNECTED 0
#define SRV_CONNECT_SUC 1
#define SRV_CONNECT_FAIL 2
#define HOST_IP @"127.0.0.1"
#define HOST_PORT 8008

#import "ViewController.h"
#import <AsyncSocket.h>

@interface ViewController () <AsyncSocketDelegate>
@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet UITextField *textField;
- (IBAction)connectButton:(id)sender;
- (IBAction)sendButton:(UIButton *)sender;


/**内容*/
@property (nonatomic, copy) NSString *content;
/**客户端socket*/
@property (nonatomic, strong) AsyncSocket *clientSocket;
/**
* 连接到服务器
*
* @param hostIP 服务器地址
* @param hostPort 端口号
*/
- (NSInteger )connecToServer:(NSString *)hostIP port:(NSInteger )hostPort;
/**
* 显示数据
*
* @param message 数据信息
*/
- (void)showMessage:(NSString *)message;

@end

@implementation ViewController

#pragma mark - View lifeCycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// [self connecToServer:HOST_IP port:HOST_PORT];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (NSInteger )connecToServer:(NSString *)hostIP port:(NSInteger)hostPort
{
if (self.clientSocket == nil) {

self.clientSocket = [[AsyncSocket alloc] initWithDelegate:self];
NSError *error = nil;
// 连接服务器
if (![self.clientSocket connectToHost:hostIP onPort:hostPort error:&error]) {
NSLog(@"Error %ld:%@", (long)error.code, [error localizedDescription]);

UIAlertController *vc = [UIAlertController alertControllerWithTitle:[@"Connection failed to host" stringByAppendingString:hostIP] message:[NSString stringWithFormat:@"%ld:%@",(long)error.code,error.localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:vc animated:YES completion:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
}];
return SRV_CONNECT_FAIL;
}else {
NSLog(@"conected server successed");
return SRV_CONNECT_SUC;
}
}else {
return SRV_CONNECTED;
}
}

- (void)showMessage:(NSString *)message
{
UIAlertController *vc = [UIAlertController alertControllerWithTitle:@"Alert!" message:message preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:vc animated:YES completion:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
}];
}


- (IBAction)connectButton:(id)sender {
NSInteger state = [self connecToServer:HOST_IP port:HOST_PORT];
switch (state) {
case SRV_CONNECT_FAIL:
[self showMessage:@"server error"];
case SRV_CONNECT_SUC:
[self showMessage:@"connect success"];
break;
case SRV_CONNECTED:
[self showMessage:@"connected already,don't do it again!"];
break;
default:
break;
}
}

- (IBAction)sendButton:(UIButton *)sender {
NSString *sendStr = self.textField.text;
NSString *content = [sendStr stringByAppendingString:@"\r\n"];
NSLog(@"%@",content);
NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
// 发送数据到服务器
[self.clientSocket writeData:data withTimeout:-1 tag:0];
}

#pragma mark - asyncScoket delegate
// 连接服务器
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
// 将要断开连接
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(@"%@",err);
}
// 已经断开连接
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSString *msg = @"Sorry this connect is failure";
[self showMessage:msg];
self.clientSocket = nil;
}
// 接收数据
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
self.content = dataStr;
NSLog(@"have received data :%@",dataStr);
NSString *newStr = [NSString stringWithFormat:@"\n%@",dataStr];
self.textView.text = newStr;
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
@end
  • 服务端
#import "SocketView.h"
#import <AsyncSocket.h>

#define WELCOME_MSG  0
#define ECHO_MSG     1
#define FORMAT(format, ...) [NSString stringWithFormat:format, ##__VA_ARGS__]

@interface SocketView () <AsyncSocketDelegate>
@property (weak) IBOutlet NSButton *stopBtn;

- (IBAction)stopButton:(id)sender;
@property (weak) IBOutlet NSTextField *logView;
@property (weak) IBOutlet NSTextField *portLabel;

/**监听socket*/
@property (nonatomic, strong) AsyncSocket *listenSocket;
/**socket连接数组*/
@property (nonatomic, strong) NSMutableArray *connectedSockets;
/**运行与否*/
@property (nonatomic, assign) BOOL isRuning;

@end

@implementation SocketView

- (void)awakeFromNib
{
    // 初始化设置
    self.listenSocket = [[AsyncSocket alloc] initWithDelegate:self];
    [self.listenSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
    self.connectedSockets = [[NSMutableArray alloc] init];
    self.isRuning = NO;
    [self.stopBtn setTitle:@"Start"];
}

- (IBAction)stopButton:(id)sender {
    if (!self.isRuning) {
        int port = [self.portLabel intValue];
        port = 8008;
        [self.portLabel setStringValue:@"8008"];
        if(port < 0 || port > 65535)
        {
            port = 0; // 会随即取端口
        }
        NSError *error = nil;
        // 开始接受客户端连接
        if (![self.listenSocket acceptOnPort:port error:&error]) {
            [self.logView setStringValue:FORMAT(@"Error starting server: %@", error)];
            return;
        }
        [self.logView setStringValue:FORMAT(@"Echo server started on port %hu", [self.listenSocket localPort])];

        self.isRuning = YES;
        [self.portLabel setEnabled:NO];
        [self.stopBtn setTitle:@"Stop"];
    }
    else
    {
        // 停止监听socket
        [self.listenSocket disconnect];

        // 断开所有客户端连接
        int i;
        for(i = 0; i < [self.connectedSockets count]; i++)
        {
              [[self.connectedSockets objectAtIndex:i] disconnect];
        }

        [self.logView setStringValue:@"Stopped Echo server"];
        self.isRuning = false;

        [self.portLabel setEnabled:YES];
        [self.stopBtn setTitle:@"Start"];
    }
}




#pragma mark - asyncSocket Delegate
/**
 *  接受客户端连接
 *
 *  @param sock      监听socket
 *  @param newSocket 新连接
 */
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
    [self.connectedSockets addObject:newSocket];
}

/**
 *  已经与客户端建立连接
 *
 *  @param sock 连接1
 *  @param host 客户端ip
 *  @param port 连接端口
 */
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    [self.logView setStringValue:FORMAT(@"Accepted client %@:%hu", host, port)];

    NSString *welcomeMsg = @"恭喜您,已经通过scoket连接上服务器!";
    NSLog(@"welcomeMsg:%@",welcomeMsg);
    NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding];
    [sock writeData:welcomeData withTimeout:-1 tag:0];
}

/**
 *  发送数据到客户端
 *
 *  @param sock 连接
 *  @param tag  标识
 */
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    [sock readDataToData:[AsyncSocket CRLFData] withTimeout:-1 tag:0];
}
/**
 *  接收客户端数据
 *
 *  @param sock 连接1
 *  @param data 数据
 *  @param tag  标识
 */
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSData *readData = [data subdataWithRange:NSMakeRange(0, data.length -2)];
    NSString *recvMessage = [[NSString alloc] initWithData:readData encoding:NSUTF8StringEncoding];
    NSString *recv = [NSString stringWithFormat:@"用户%zd:%@",[self.connectedSockets indexOfObject:sock],recvMessage];
    if (recvMessage) {
        [self.logView setStringValue:recv];
        NSLog(@"%@",recv);
    }
    else
    {
        [self.logView setStringValue:@"Error converting received data into UTF-8 String"];
        NSLog(@"Error converting received data into UTF-8 String");
    }
    NSString *backStr = nil;
    for (AsyncSocket *subSock in self.connectedSockets) {
        if ([subSock isEqual:sock]) {
            backStr = [NSString stringWithFormat:@"我说: %@",recvMessage];
        }
        else
        {
            backStr = [NSString stringWithFormat:@"ta说: %@",recvMessage];
        }
    }
    // 回发数据
    NSData* backData = [backStr dataUsingEncoding:NSUTF8StringEncoding];
    [sock writeData:backData withTimeout:-1 tag:0];
}

/**
 *  将要断开连接
 *
 *  @param sock 连接1
 *  @param err  错误码
 */
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
    [self.logView setStringValue:FORMAT(@"Client Disconnected: %@:%hu", [sock connectedHost], [sock connectedPort])];
    NSLog(@"%@",FORMAT(@"Client Disconnected: %@:%hu", [sock connectedHost], [sock connectedPort]));
}

/**
 *  已经断开连接·
 *
 *  @param sock 连接1
 */
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
    [self.connectedSockets removeObject:sock];
}

- (BOOL)onSocketWillConnect:(AsyncSocket *)sock
{
    return YES;
}

@end
文章目录
  1. 1. socket编程
    1. 1.1. CocoaAsyncSocket
    2. 1.2. AsyncSocket使用
      1. 1.2.1. 大概过程
      2. 1.2.2. 客户端-服务端
    3. 1.3. 关键代码