不要急,不要怕

基于socket的“抽奖”

socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接,UDP连接同理。

原理图

AsyncUdpSocket:

这里用到了一个三方AsyncUdpSocket,原来的下载地址不过现在不能用了,github有类似的,应该也可以直接用。这套抽奖是socket的及其简单的应用,写两套代码分别给操作端和现实端。

先来张图
抽奖时用的是随机数对20取余,而最后的“现在”就是通过socket发送到现实端的。

显示端:

代码很简单,这里我就直接粘了:

#import "ViewController.h"
#import "AsyncUdpSocket.h"
#import <AVFoundation/AVFoundation.h>

#define RandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]//随机色

#define screenWidth [UIScreen mainScreen].bounds.size.width
#define screenHeight [UIScreen mainScreen].bounds.size.height


@interface ViewController ()<AsyncUdpSocketDelegate>{
AsyncUdpSocket *_socket;
NSTimer *_timer;
NSString *_lastStr;
UIButton *startBut;


}

@property (nonatomic,strong)AVPlayer *player;
@property (nonatomic,strong)UILabel *label;

@end

@implementation ViewController

//懒加载播放器
- (AVPlayer *)player{
if (_player == nil) {
    // 1.获取URL(远程/本地)
     NSURL *url = [[NSBundle mainBundle] URLForResource:@"M11-01-05-57.mp3" withExtension:nil];
    //NSURL *url = [NSURL URLWithString:@"http://v1.mukewang.com/a45016f4-08d6-4277-abe6-bcfd5244c201/L.mp4"];

    // 2.创建AVPlayerItem
    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];

    // 3.创建AVPlayer
    _player = [AVPlayer playerWithPlayerItem:item];

    // 4.添加AVPlayerLayer
    AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    layer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.width * 9 / 16);
    [self.view.layer addSublayer:layer];
}
return _player;}

//搭建页面    
- (void)viewDidLoad {
[super viewDidLoad];

_label = [[UILabel alloc] initWithFrame:CGRectMake(screenWidth/2-150, 100, 300, 300)];
_label.backgroundColor = [UIColor orangeColor];
_label.font = [UIFont systemFontOfSize:33.0f weight:21];
_label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:self.label];

startBut = [[UIButton alloc] initWithFrame:CGRectMake(screenWidth/2-50, screenHeight-200, 100, 50)];
[startBut setBackgroundColor:[UIColor redColor]];
[startBut setTitle:@"开始抽奖" forState:UIControlStateNormal];
[startBut addTarget:self action:@selector(LetUsBegin) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:startBut];



_socket = [[AsyncUdpSocket alloc]initIPv4];
_socket.delegate = self;
//ip 和 端口号//这个重电脑的网络看,必需要一致
[_socket bindToAddress:@"10.10.5.32" port:9444 error:nil];

//保持连接
[_socket receiveWithTimeout:-1 tag:0];

}

//点击了开始抽奖按钮

- (void)LetUsBegin{
 startBut.hidden = YES;
[self.player play];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:@selector(ChangeLabelText) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(9* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self stopTimer];
});

}

10秒过后停止

- (void)stopTimer{
[_timer invalidate];
_timer = nil;
if (_lastStr) {
     _label.text  = _lastStr;
}else{
    _label.text = [NSString stringWithFormat:@"%i",arc4random()%30];
}
   startBut.hidden = NO;
_label.backgroundColor = RandomColor;
_lastStr = nil;
self.player = nil;
}

定时器方法,

- (void)ChangeLabelText{
_label.text = [NSString stringWithFormat:@"%i",arc4random()%20];
_label.backgroundColor = RandomColor;

}

socket代理方法

-(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{

_lastStr =  [[NSString alloc] initWithData:data  encoding:NSUTF8StringEncoding];
  //保持连接
    [_socket receiveWithTimeout:-1 tag:0];
 return YES;

}

控制端:

控制端的样式
下面放代码:

#import "ViewController.h"
#import "AsyncUdpSocket.h"
#include <ifaddrs.h>
#include <arpa/inet.h>

@interface ViewController (){
  AsyncUdpSocket *_socket;
NSString *_ipAddress;
}

@property (nonatomic,strong)UITextField *tf;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

//输入框
_tf = [[UITextField alloc] initWithFrame:CGRectMake(20, 100, 200, 50)];
_tf.backgroundColor = [UIColor grayColor];
[self.view addSubview:_tf];

//获取ip地址
_ipAddress = [self deviceIPAdress];
NSLog(@"%@",_ipAddress);

UIButton *but = [[UIButton alloc] initWithFrame:CGRectMake(200, 200, 80, 30)];
[but setBackgroundColor:[UIColor redColor]];
[but setTitle:@"发送" forState:UIControlStateNormal];
[but addTarget:self action:@selector(sendTheNumber) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:but];
}

//初始化socket和发送ip

- (void)sendTheNumber{
_socket = [[AsyncUdpSocket alloc]initIPv4];
_socket.delegate = self;
//ip 和 端口号
[_socket bindToAddress:_ipAddress port:9444 error:nil];

//[_socket sendData:data toAddress:@"192.168.1.160" withTimeout:-1 tag:0];

NSData* data = [_tf.text dataUsingEncoding:NSUTF8StringEncoding];

[_socket sendData:data toHost:@"10.10.5.38" port:9444 withTimeout:-1 tag:0];

_tf.text = @"";
//保持连接
[_socket receiveWithTimeout:-1 tag:0];
}

- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{

return YES;

}

//wifi下获取手机ip的方法

- (NSString *)deviceIPAdress {
NSString *address = @"an error occurred when obtaining ip address";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;

success = getifaddrs(&interfaces);

if (success == 0) { // 0 表示获取成功

    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;
    }
}

freeifaddrs(interfaces);

NSLog(@"手机的IP是:%@", address);
return address;

}