概述
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8734 //将端口设置为8734,可以根据具体情况改变
@interface ViewController : UIViewController<NSStreamDelegate>
{
int flag ; //操作标志 0为发送 1为接收
}
@property (nonatomic, retain) NSInputStream *inputStream;
@property (nonatomic, retain) NSOutputStream *outputStream;
@property (weak, nonatomic) IBOutlet UILabel *message; //在客户端显示来自服务端的消息
- (IBAction)sendData:(id)sender; //发送客户端的消息
- (IBAction)receiveData:(id)sender; //接收来自服务端的消息
@end
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//初始化客户端网络连接
- (void)initNetworkCommunication
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
//这里需要填写 IP 地址,根据自己路由可以用的 IP来定,这里是192.168.1.103,如果不知道可以下载 IP 扫描器
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.1.103", PORT, &readStream, &writeStream);
self.inputStream = (__bridge_transfer NSInputStream *)readStream; //将CFStream对象转化为NSStream对象
self.outputStream = (__bridge_transfer NSOutputStream
*)writeStream; //将CFStream对象转化为NSStream对象
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode]; //NSStream 方法 scheduleInRunLoop: 设置 Run Loop
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[self.inputStream open]; //NSStream 的 open 方法来打开数据流对象
[self.outputStream open];
}
//关闭数据流操作
-(void)close
{
[self.outputStream close];
[self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream setDelegate:nil];
[self.inputStream close];
[self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream setDelegate:nil];
}
//从客户端发送数据事件方法
- (IBAction)sendData:(id)sender {
flag = 0; //表示发送
[self initNetworkCommunication];
}
//从服务端接收数据事件方法
- (IBAction)receiveData:(id)sender {
flag = 1; //表示接收
[self initNetworkCommunication];
}
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSString *event;
switch (streamEvent) {
case NSStreamEventNone: //没有事件发生
event = @"NSStreamEventNone";
break;
case NSStreamEventOpenCompleted: //成功打开流
event = @"NSStreamEventOpenCompleted";
break;
case NSStreamEventHasBytesAvailable: //这个流有数据可以读,在读取数据时使用
event = @"NSStreamEventHasBytesAvailable";
if (flag ==1 && theStream == _inputStream) {
NSMutableData *input = [[NSMutableData alloc] init];
uint8_t buffer[2048]; //读取数据准备缓冲区,本例中设置的是2048字节,这个大小会对流的读取有很大影响
int len;
while([self.inputStream hasBytesAvailable])
{
len = [self.inputStream read:buffer maxLength:sizeof(buffer)]; //读取数据到缓冲区
if (len > 0)
{
[input appendBytes:buffer length:len];
}
}
NSString *resultstring = [[NSString alloc] initWithData:input encoding:NSUTF8StringEncoding];
NSLog(@"接收:%@",resultstring);
self.message.text = resultstring;
}
break;
case NSStreamEventHasSpaceAvailable: //这个流可以接收数据的写入,在写数据时使用
event = @"NSStreamEventHasSpaceAvailable";
if (data && data.length != 0) {
if (theStream == _outputStream) {
//输出
NSString * snStr = [NSString stringWithFormat:@"%@",[_dic objectForKey:@"sn"]];
NSString * comStr = [NSString stringWithFormat:@"%@",data ];
const char * comChar = [comStr UTF8String];
char * comUnit = [[comStr dataUsingEncoding:NSUTF8StringEncoding]bytes];
strcpy(comUnit, comChar);
if ([comStr intValue] == 0) {
comUnit[0] = 00;
}else if ([comStr intValue] == 1){
comUnit[0] = 01;
}else if ([comStr intValue] == 2){
comUnit[0] = 02;
}
// memcpy(comUnit,[comStr UTF8String], [comStr length]+1);
const char * snChar = [snStr UTF8String];
char * bufChar = [[snStr dataUsingEncoding:NSUTF8StringEncoding]bytes];
strcpy(bufChar, snChar);
UInt8 i=0;
unsigned char tcpcmd[44]={(char)0x00,(char)0x2C,(char)0xAA,(char)0x55,(char)0x0,(char)0x0,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x31,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x39,(char)0x31,(char)0x04 };
while(strlen(bufChar)!=0)
{
tcpcmd[31+i]=*bufChar++;
i++;
}
tcpcmd[43]=*comUnit;
NSData *senddata = [NSData dataWithBytes: tcpcmd length:44];
NSLog(@"tcpcmd-%d",strlen((const char*)tcpcmd)+1);
[_outputStream write:[senddata bytes] maxLength: 44];
//必须关闭输出流否则,服务器端一直读取不会停止,
[_outputStream close];
}
data = @"";
// [self alter:@"操作成功"];
[self performSelector:@selector(getState) withObject:nil afterDelay:2.0f];
}
break;
case NSStreamEventErrorOccurred: //数据流发生错误
event = @"NSStreamEventErrorOccurred";
[self close];
break;
case NSStreamEventEndEncountered: //数据流结束
event = @"NSStreamEventEndEncountered";
NSLog(@"Error:%d:%@",[[theStream streamError] code], [[theStream streamError] localizedDescription]);
break;
default:
[self close];
event = @"Unknown";
break;
}
}
@end
//---------------------------------------------------------------------------------------------------------------------
在iOS开发中使用socket,一般都是用第三方库AsyncSocket,不得不承认这个库确实很强大。下载地址CocoaAsyncSocket
导入
AsyncSocket.h
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
enum{
SocketOfflineByServer,// 服务器掉线,默认为0
SocketOfflineByUser, // 用户主动cut
SocketOfflineByWifiCut,
};
@interface LGSocketServe : NSObject<AsyncSocketDelegate>
@property (nonatomic, strong) AsyncSocket *socket; // socket
@property (nonatomic, retain) NSTimer *heartTimer; // 心跳计时器
// socket连接
- (void)startConnectSocket;
+ (LGSocketServe *)sharedSocketServe;
-(void)cutOffSocket;
// 发送消息
- (void)sendMessage:(id)message;
@end
#import "LGSocketServe.h"
//自己设定
#define HOST @"192.168.1.218"
#define PORT 9091
#define TIME_OUT 20
#define MAX_BUFFER 1024
#define READ_TIME_OUT -1
#define WRITE_TIME_OUT -1
@implementation LGSocketServe
static LGSocketServe *socketServe = nil;
#pragma mark public static methods
+ (LGSocketServe *)sharedSocketServe {
@synchronized(self) {
if(socketServe == nil) {
socketServe = [[[self class] alloc] init];
}
}
return socketServe;
}
+(id)allocWithZone:(NSZone *)zone
{
@synchronized(self)
{
if (socketServe == nil)
{
socketServe = [super allocWithZone:zone];
return socketServe;
}
}
return nil;
}
- (void)startConnectSocket
{
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
[self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
if ( ![self SocketOpen:HOST port:PORT] )
{
}
}
-(void)cutOffSocket
{
self.socket.userData = SocketOfflineByUser;
[self.socket disconnect];
}
- (NSInteger)SocketOpen:(NSString*)addr port:(NSInteger)port
{
if (![self.socket isConnected])
{
NSError *error = nil;
[self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error];
}
return 0;
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
//这是异步返回的连接成功,
NSLog(@"didConnectToHost");
//通过定时器不断发送消息,来检测长连接
self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
[self.heartTimer fire];
}
// 心跳连接
-(void)checkLongConnectByServe{
// 向服务器发送固定可是的消息,来检测长连接
NSString *longConnect = @"connect is here";
NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:1 tag:1];
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(@"7878 sorry the connect is failure %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服务器掉线,重连
[self startConnectSocket];
}
else if (sock.userData == SocketOfflineByUser) {
// 如果由用户断开,不进行重连
return;
}else if (sock.userData == SocketOfflineByWifiCut) {
// wifi断开,不进行重连
return;
}
}
- (void)sendMessage:(id)message
{
//像服务器发送数据
// NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:message withTimeout:WRITE_TIME_OUT tag:1];
}
//发送消息成功之后回调
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
//读取消息
[self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
}
//接受消息成功之后回调
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//服务端返回消息数据量比较大时,可能分多次返回。所以在读取消息的时候,设置MAX_BUFFER表示每次最多读取多少,当data.length < MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析
if( data.length < MAX_BUFFER )
{
//收到结果解析...
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@",dic);
//解析出来的消息,可以通过通知、代理、block等传出去
}
[self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSData * unreadData = [sock unreadData]; // ** This gets the current buffer
if(unreadData.length > 0) {
[self onSocket:sock didReadData:unreadData withTag:0]; // ** Return as much data that could be collected
} else {
NSLog(@" willDisconnectWithError %ld err = %@",sock.userData,[err description]);
if (err.code == 57) {
self.socket.userData = SocketOfflineByWifiCut;
}
}
}
@end
最后
以上就是顺利冰棍为你收集整理的iOS中基于Socket 的的网络通信的全部内容,希望文章能够帮你解决iOS中基于Socket 的的网络通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复