由于项目需要,需要和安卓在没网的情况下传递数据,所以研究了一下“wifi通信”和“蓝牙”
1,蓝牙(随便说一下)
首先声明,蓝牙这条书走不通,下面是我的尝试
安卓机可以搜索到苹果的蓝牙,但是苹果手机无法搜索到安卓机的蓝牙(苹果4s是可以搜索到的),链接苹果机开启配对,也可以配对成功,但是 配对密码是无用的,苹果机是直接就连上了,之后ios程序里 关于蓝牙的回调和各种代理方法失效,好像只是蓝牙连上了,没有后续!蓝牙宣告结束
2,wifi链接
特别注意:与安卓互联的时候需要在发送的字符串后面加上"\r\n",这是一个传输协议
下面是几个参考的链接,目前只能传数字和字母(汉字会失败)
@http://qk13warcraft.blog.163.com/blog/static/1575493442012778524173/
下面这个是用到的第三方库的地址
@https://git.oschina.net/zdsoft/AsyncSocket-SeverDemoAndClientDemo
1,下载第三方库到本地 找到 并拉入项目中
2,拉入四个官方的库
23,把这个文件改成MRC(在后面加上-fno-objc-arc)
34,至此,准备工作做完了,开始加入代码(服务器端)
引入头文件
#import "AsyncSocket.h"
宏定义
#define WELCOME_MSG 0
#define ECHO_MSG 1
#define WARNING_MSG 2
#define READ_TIMEOUT 5.0
#define READ_TIMEOUT_EXTENSION 10.0
声明变量
@implementation ViewController{
AsyncSocket *listenSocket;
NSMutableArray *connectedSockets;
BOOL isRunning;
UITextField *tfSender;
UIButton *btnSend;
UIButton *btnPort;
}
//初始化AsyncSocket
- (void)initAsyncSocket{
listenSocket = [[AsyncSocket alloc] initWithDelegate:self];
connectedSockets = [[NSMutableArray alloc] initWithCapacity:1];
isRunning = NO;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initAsyncSocket];
NSLog(@"Ready");
// Advanced options - enable the socket to contine operations even during modal dialogs, and menu browsing
NSArray *arr = [NSArray arrayWithObject:NSRunLoopCommonModes];
NSLog(@"%@",arr);
[listenSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
[listenSocket readDataWithTimeout:-1 tag:0];
// 设置要连接的port
btnPort = [[UIButton alloc]initWithFrame:CGRectMake(10, 150, 100, 30)];
[self.view addSubview:btnPort];
[btnPort addTarget:self action:@selector(setstart:) forControlEvents:UIControlEventTouchUpInside];
[btnPort setBackgroundColor:[UIColor orangeColor]];
[btnPort setTitle:@"开始" forState:UIControlStateNormal];
tfSender = [[UITextField alloc]initWithFrame:CGRectMake(10, 200, 200, 30)];
[self.view addSubview:tfSender];
[tfSender setPlaceholder:@"请输入发送内容"];
[tfSender setBackgroundColor:[UIColor yellowColor]];
[tfSender setKeyboardType:UIKeyboardTypeNumberPad];
btnSend = [[UIButton alloc]initWithFrame:CGRectMake(220, 200, 60, 30)];
[self.view addSubview:btnSend];
[btnSend addTarget:self action:@selector(sendMessage) forControlEvents:UIControlEventTouchUpInside];
[btnSend setBackgroundColor:[UIColor orangeColor]];
[btnSend setTitle:@"发送" forState:UIControlStateNormal];
}
- (void)sendMessage{
[tfSender resignFirstResponder];
NSString *str = tfSender.text;
NSLog(@"发送的内容:%@",str);
NSData *data=[str dataUsingEncoding:NSUTF8StringEncoding];
[listenSocket writeData:data withTimeout:-1 tag:1];
}
//开始 设置port
- (void)setstart:(id)sender {
[listenSocket readDataWithTimeout:-1 tag:0];
if(!isRunning)
{
int port = 8080;
if(port < 0 || port > 65535)
{
port = 0;
}
NSError *error = nil;
if(![listenSocket acceptOnPort:port error:&error])
{
return;
}
isRunning = YES;
[btnPort setTitle:@"停止" forState:UIControlStateNormal];
}
else
{
// Stop accepting connections
[listenSocket disconnect];
// Stop any client connections
int i;
for(i = 0; i < [connectedSockets count]; i++)
{
// Call disconnect on the socket,
// which will invoke the onSocketDidDisconnect: method,
// which will remove the socket from the list.
[[connectedSockets objectAtIndex:i] disconnect];
}
isRunning = false;
[btnPort setTitle:@"开始" forState:UIControlStateNormal];
}
}
//下面是代理方法
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
[connectedSockets addObject:newSocket];
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
// [self logInfo:FORMAT(@"Accepted client %@:%hu", host, port)];
NSString *welcomeMsg = @"连接到服务器了\r\n";
NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:welcomeData withTimeout:-1 tag:WELCOME_MSG];
[sock readDataToData:[AsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
if(tag == ECHO_MSG)
{
[sock readDataToData:[AsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0];
}
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length] - 2)];
NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
if(msg)
{
NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客户端发送来的是:%@",str);
str =[str stringByAppendingString:@"这是服务器回的"];
NSData *data=[str dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:data withTimeout:-1 tag:1];
listenSocket = sock;
}
else
{
// [self logError:@"Error converting received data into UTF-8 String"];
}
// Even if we were unable to write the incoming data to the log,
// we're still going to echo it back to the client.
// [sock writeData:data withTimeout:-1 tag:ECHO_MSG];
}
/**
* This method is called if a read has timed out.
* It allows us to optionally extend the timeout.
* We use this method to issue a warning to the user prior to disconnecting them.
**/
- (NSTimeInterval)onSocket:(AsyncSocket *)sock
shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(CFIndex)length
{
if(elapsed <= READ_TIMEOUT)
{
NSString *warningMsg = @"哈哈 我是服务器\r\n";
NSData *warningData = [warningMsg dataUsingEncoding:NSUTF8StringEncoding];
[sock writeData:warningData withTimeout:-1 tag:WARNING_MSG];
return READ_TIMEOUT_EXTENSION;
}
return 0.0;
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(@"Client Disconnected: %@:%hu",[sock connectedHost],[sock connectedPort]);
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
[connectedSockets removeObject:sock];
}
5,下面是客户端代码
//引入头文件 宏定义
#import "AsyncSocket.h"
//首先导入头文件信息
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
#define IOS_CELLULAR @"pdp_ip0"
#define IOS_WIFI @"en0"
//#define IOS_VPN @"utun0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
@interface ViewController ()
@property (retain,nonatomic)AsyncSocket *client;
@end
@implementation ViewController{
UITextField *tfSend;
UILabel *lblbackContent;
NSString *ipStr;
int portInt;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btnSure = [[UIButton alloc]initWithFrame:CGRectMake(10, 180, 160, 40)];
[self.view addSubview:btnSure];
[btnSure setBackgroundColor:[UIColor orangeColor]];
[btnSure addTarget:self action:@selector(ClientToSever) forControlEvents:UIControlEventTouchUpInside];
[btnSure setTitle:@"连接到服务器" forState:UIControlStateNormal];
// 发送内容
tfSend = [[UITextField alloc]initWithFrame:CGRectMake(10, 230, 200, 30)];
[self.view addSubview:tfSend];
[tfSend setBackgroundColor:[UIColor yellowColor]];
[tfSend setPlaceholder:@"发送内容"];
UIButton *btnSend = [[UIButton alloc]initWithFrame:CGRectMake(10, 270, 60, 40)];
[self.view addSubview:btnSend];
[btnSend setBackgroundColor:[UIColor orangeColor]];
[btnSend addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside];
[btnSend setTitle:@"发送" forState:UIControlStateNormal];
// 服务器返回内容
lblbackContent = [[UILabel alloc]initWithFrame:CGRectMake(10, 320, 340, 200)];
[self.view addSubview:lblbackContent];
lblbackContent.text = @"服务器返回的数据:";
[lblbackContent setBackgroundColor:[UIColor yellowColor]];
lblbackContent.numberOfLines = 10;
}
-(int)connectSever{
//先获取本机链接的热点的ip
ipStr = [self getIPAddress:YES];
//获取服务器端的ip
ipStr = [ipStr substringToIndex:ipStr.length - 1];
ipStr = [NSString stringWithFormat:@"%@1",ipStr];
portInt = 8080;
if (_client==nil) {
_client =[[AsyncSocket alloc]initWithDelegate:self];
NSError *error=nil;
if (![_client connectToHost:ipStr onPort:portInt error:&error]) {
NSLog(@" error --- %@ %@",error,[error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection failed to host" message:@"error" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"YES", nil];
[alert show];
return 2;
}
//
else{
NSLog(@"连接成功");
return 1;
}
}
else{
[_client readDataWithTimeout:-1 tag:0];
return 0;
}
}
//连接服务器
- (void)ClientToSever {
int state =[self connectSever];
switch (state) {
case 1:
[self showMessage:@"连接成功"];
break;
case 2:
[self showMessage:@"连接失败"];
break;
case 0:
[self showMessage:@"不必再连,已连接"];
break;
default:
break;
}
}
//发送信息
- (void)sendMessage:(id)sender {
[tfSend resignFirstResponder];
NSString *str = tfSend.text;
NSString *content =[str stringByAppendingString:@"\r\n"];
NSLog(@"str --->%@",content);
NSData *data4=[content dataUsingEncoding:4];
[_client writeData:data4 withTimeout:-1 tag:0];
}
- (void) showMessage:(NSString *) msg{
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"Alert!"
message:msg
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
#pragma mark -- Asy ---Soc Delegate
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
[_client readDataWithTimeout:-1 tag:0];
NSLog(@"Delegate... 连接上服务器了,监听中");
}
-(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
NSLog(@"Delegate...发生错误:%@",err);
}
-(void)onSocketDidDisconnect:(AsyncSocket *)sock{
NSString *msg=@"连接失败";
[self showMessage:msg];
_client=nil;
NSLog(@"Delegate...连接失败");
}
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSArray *arrbackc = [str componentsSeparatedByString:@"\r\n"];
if (arrbackc.count == 2) {
NSData *backData4 = [arrbackc[0] dataUsingEncoding:4];
NSString *strContent4 = [[NSString alloc]initWithData:backData4 encoding:4];
str = [NSString stringWithFormat:@"%@",strContent4];
}
NSLog(@"Delegate...接收到的数据是%@",str);
lblbackContent.text=str;
// [str release];
[_client readDataWithTimeout:-1 tag:0];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSString *)getIPAddress:(BOOL)preferIPv4
{
NSArray *searchArray = preferIPv4 ?
@[ /*IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6,*/ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
@[ /*IOS_VPN @"/" IP_ADDR_IPv6, IOS_VPN @"/" IP_ADDR_IPv4,*/ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
NSDictionary *addresses = [self getIPAddresses];
NSLog(@"addresses: %@", addresses);
__block NSString *address;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
{
address = addresses[key];
if(address) *stop = YES;
} ];
return address ? address : @"0.0.0.0";
}
//获取所有相关IP信息
- (NSDictionary *)getIPAddresses
{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
6,操作步骤,demo正常运行之后
服务器端操作
(1):作为服务器端的手机关闭wifi和蓝牙(不关闭的话,发出的热点,另外一个手机搜索不到)
问题解释 1
(2):
2(3):
3
(4):
4(5):
5(6):
6客户端操作:
(1):
(2):
client2(3):
client3(4):
client4(5):
client5(6):
client6
网友评论