本人刚刚从事ios开发半年, 前几天想了解一下苹果的Socket编程, 然后去百度东西, 发现许多人都是建议使用AsyncSocket, 然后就去了解了一下, 现在我把我的学习经验总结一下, 哪里说的不对还望赐教。
想学习Socket,先去了解一下TCP和UDP,原理的东西还是自己去百度吧。
在ios中使用Socket可以使用封装好的AsyncSocket库, 用来简化对CFNetwork的调用。你需要从网上下载AsyncSocket 库, 里面一共有四个文件, 全部拖到工程中,如果你的程序是ARC的,需要改一下 -fno-objc-arc
我先说明我的程序的功能,这样你就很容易看懂了,我在页面上放了一个大大的UITextField,用来接受从服务器返回来的数据,下面是一个UITextField,用来输入内容,最下面是三个按钮-连接-发送-断开连接
现在我开始贴代码了,代码可能看着不明朗, 我把xcode截图可以看图片
客户端:
//
// RootViewController.m
// SocketTest
//
// Created by mac on 15/1/29.
// Copyright (c) 2015年 MAC. All rights reserved.
//
#import "RootViewController.h"
#import "AsyncSocket.h"
#define Ksize self.view.bounds.size
@interface RootViewController ()<UITextFieldDelegate>
{
AsyncSocket* socketTest;
UITextField* SendText;
UITextView* historyLabel;
NSMutableString* historyStr;
}
@end
@implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
historyStr=[[NSMutableString alloc]init];
// [self connAction];
historyLabel=[[UITextView alloc]initWithFrame:CGRectMake(20, 64, Ksize.width-40, Ksize.height-150-64)];
historyLabel.userInteractionEnabled=NO;
[historyLabel setBackgroundColor:[UIColor grayColor]];
[self.view addSubview:historyLabel];
SendText=[[UITextField alloc]initWithFrame:CGRectMake(20, Ksize.height-110, Ksize.width-40, 40)];
[SendText setBackgroundColor:[UIColor grayColor]];
SendText.delegate=self;
[self.view addSubview:SendText];
UIButton* connectBtn=[UIButton buttonWithType:UIButtonTypeSystem];
[connectBtn setFrame:CGRectMake(20, Ksize.height-50, 100, 50)];
[connectBtn setTitle:@"连接" forState:UIControlStateNormal];
[connectBtn addTarget:self action:@selector(connAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:connectBtn];
UIButton* btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn1 setTitle:@"发送" forState:UIControlStateNormal];
[btn1 setFrame:CGRectMake(CGRectGetMaxX(connectBtn.frame), Ksize.height-50, 50, 50)];
[btn1 addTarget:self action:@selector(sendAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn1];
UIButton* disconnBtn=[UIButton buttonWithType:UIButtonTypeSystem];
[disconnBtn setTitle:@"断开连接" forState:UIControlStateNormal];
[disconnBtn setFrame:CGRectMake(CGRectGetMaxX(btn1.frame), Ksize.height-50, 150, 50)];
[disconnBtn addTarget:self action:@selector(disconnectAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:disconnBtn];
}
-(void)disconnectAction{
//断开已有的连接
[socketTest disconnect];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
//连接到指定的服务器
-(void)connAction
{
if (!socketTest) {
//初始化并设置代理 需要遵守协议AsyncSocketDelegate
socketTest = [[AsyncSocket alloc]initWithDelegate:self];
}
//如果已经连接到指定服务器
if ([socketTest isConnected]) {
//断开已有的连接
[socketTest disconnect];
}
//用clientSocket ,连接到指定的服务器(服务器有固定的ip地址和端口)
// 固定的写法,自己本机的ip地址
[socketTest connectToHost:@"192.168.1.115" onPort:5678 error:Nil];
}
#pragma mark- async aocket delegate
//与指定服务器连接后,出触发这个方法
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"与服务器:%@ %d 发起连接",host,port);
[socketTest readDataWithTimeout: -1 tag: 10];
}
//向服务端发送消息
-(void)sendAction:(UIButton*)sender
{
[historyStr appendString:[NSString stringWithFormat:@"%@\n",SendText.text]];
//转换成data
NSData* data=[[NSString stringWithFormat:@"%@",SendText.text] dataUsingEncoding:NSUTF8StringEncoding];
//向指定服务器发送消息
//timeout代表无限时的发送
//tag对当前操作的标记
[socketTest writeData:data withTimeout:-1 tag:0];
SendText.text=@"";
}
//消息发送完毕,出发的方法
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"send!");
}
//读取服务器的数据
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *msg = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
NSString* history= [NSString stringWithFormat:@"%@\n",msg];
historyLabel.text=history;
[socketTest readDataWithTimeout: -1 tag: 10];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
下来是服务器端的代码
先给你说说怎么用xcode创建一个mac工程,选中我标记的那个就行了
然后将AsyncSocket的四个文件导入进去
开始贴代码了
//新建工程,建的该工程
#import <Cocoa/Cocoa.h>//cocoa 是苹果封装的mac软件开发的框架,ios开发的框架叫CocoaTouch
#import "AsyncSocket.h"
@interface DCAppDelegate : NSObject <NSApplicationDelegate,AsyncSocketDelegate>
@property (assign) IBOutlet NSWindow *window;
@end
//
// DCAppDelegate.m
// TCPServer
//
// Created by qianfeng on 14-9-22.
// Copyright (c) 2014年 MAC. All rights reserved.
//
#import "DCAppDelegate.h"
@implementation DCAppDelegate{
AsyncSocket* _serverSocket;//用于监听指定的ip和端口,看是否客户端连入
NSMutableArray* _scoketArray;//用于存放与客户端交互的socket对象
NSMutableString* postString;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
_scoketArray=[[NSMutableArray alloc]init];
postString=[[NSMutableString alloc]init];
//0.2秒之后,self调用createServer方法
[self performSelector:@selector(createServer) withObject:Nil afterDelay:0.2];
}
-(void)createServer{
//初始化设置代理
_serverSocket=[[AsyncSocket alloc]initWithDelegate:self];
//负责监听指定的ip和端口,看是否有客户端接入
_serverSocket.delegate=self;
//ip可以不写
[_serverSocket acceptOnPort:5678 error:Nil];
}
#pragma mark async delegate
//当服务端收到客户端的链接是,出发此方法
//newSocket 服务端自动创建的新的socket对象,用于处理与链接的客户端的交互
-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
NSLog(@"accept!");
NSLog(@"IP:%@",[newSocket connectedHost]);
//添加到数组中维护
[_scoketArray addObject:newSocket];
//-1 不限时的监听
[newSocket readDataWithTimeout:-1 tag:0];
}
//服务端收到客户端的消息后,出发此方法
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//data 客户端发送过来的消息
NSString* str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
[postString appendString:[NSString stringWithFormat:@"%@:%@\n",[sock connectedHost],str]];
//让sock继续监听客户端是否发来消息
[sock readDataWithTimeout:-1 tag:2];
//向客户端发送消息
NSData* postData=[postString dataUsingEncoding:NSUTF8StringEncoding];
for (AsyncSocket* clientSocket in _scoketArray) {
[clientSocket writeData:postData withTimeout:-1 tag:10];
}
}
//消息发送完毕,出发的方法
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"message did write");
[_serverSocket readDataWithTimeout:-1 tag:1];
}
//如果客户端关闭,或者长期处于不活跃的状态,就会断开与服务端的链接
-(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
NSLog(@"即将断开");
}
//客户端已经断开链接
-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(@"已经断开");
}
@end