前奏:socket兩套庫坞靶,GCDAsyncSocket辽剧,GCDAsyncUdpSocket和AsyncSocket排截,AsyncUdpSocket娱节。
前者支持ARC挠蛉。什么TCP,UDP基礎(chǔ)知識就不在這里啰嗦了。
*** pods導(dǎo)入方式:pod 'CocoaAsyncSocket' ***
iOS-Socket-UDP篇
一進(jìn)入正題先上(AsyncUdpSocket)非ARC的版本1:客戶端點(diǎn)對點(diǎn)
#import "AsyncUdpSocket.h" //導(dǎo)入頭文件
AsyncUdpSocketDelegate //加入需要遵循的協(xié)議代理
// 收發(fā)套接字對象
AsyncUdpSocket * _sendSocket;//套接字發(fā)送對象
AsyncUdpSocket * _recvSocket;//套接字接收對象
收發(fā)套接字對象實(shí)例化
- (void)initSocket
{
_sendSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
// 綁定一個端口 發(fā)數(shù)據(jù)
[_sendSocket bindToPort:0x1234 error:nil];
_recvSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
[_recvSocket bindToPort:0x4321 error:nil];
// 0x1234端口做數(shù)據(jù)發(fā)送 0x4321端口接受數(shù)據(jù)
// 開始監(jiān)聽
[_recvSocket receiveWithTimeout:-1 tag:200];
// 將聊天內(nèi)容展示在表格上 自己說的顯示在左邊 別人說的現(xiàn)在在右邊 聊天內(nèi)容越長Cell高度越高
}
指定目標(biāo)端口向其發(fā)送數(shù)據(jù)
- (IBAction)sendMsg:(UIButton *)sender {
// 發(fā)送消息
// 發(fā)送消息對應(yīng)的二進(jìn)制 目標(biāo)主機(jī) 目標(biāo)主機(jī)對應(yīng)的端口號 超時時間 消息的標(biāo)簽
// 消息必須發(fā)送到接受端綁定的端口之上才能收到數(shù)據(jù)
[_sendSocket sendData:[inputField.text dataUsingEncoding:NSUTF8StringEncoding] toHost:destIPField.text port:0x4321 withTimeout:60 tag:100];
}
AsyncUdpSocket相關(guān)代理方法
- (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
NSLog(@"消息發(fā)送成功回調(diào)");
}
// 成功接受到數(shù)據(jù)回調(diào)
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
// data發(fā)送內(nèi)容的二進(jìn)制 tag消息標(biāo)簽 host發(fā)送消息的主機(jī)IP port發(fā)送方對應(yīng)的端口
NSString * content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"收到目標(biāo)IP%@端口%x說:%@",host,port,content);
// _recvSocket對象接受完數(shù)據(jù)后 必須繼續(xù)監(jiān)聽 否則不能收到數(shù)據(jù)
// -1 表示一直等 直到有數(shù)據(jù)到來
[_recvSocket receiveWithTimeout:-1 tag:200];
return YES;
}
點(diǎn)對點(diǎn)基本操作就這么簡單肄满,實(shí)際通信開發(fā)中需要的也許遠(yuǎn)遠(yuǎn)不止如此了谴古,這里純抽出的是點(diǎn)對點(diǎn)點(diǎn)對點(diǎn)關(guān)鍵代碼沒有貼UI相關(guān)。操作效果截圖如下:
二.ARC的版本1:客戶端點(diǎn)對點(diǎn)
#define recvPort 2346 //接收socket端口
#define sendPort 6432 //發(fā)送socket端口
@import CocoaAsyncSocket;//導(dǎo)入頭文件
#*** pods導(dǎo)入方式:pod 'CocoaAsyncSocket' ***#
GCDAsyncUdpSocketDelegate 需要遵循的代理協(xié)議
GCDAsyncUdpSocket *_sendSocket;//發(fā)送socket
GCDAsyncUdpSocket *_recvSocket;//接收socket
@property (strong, nonatomic) UITextField *ipText;//發(fā)送目標(biāo)的IP地址
- (void)viewDidLoad {
[super viewDidLoad];
[self initSocket];
_submitText=[[UITextField alloc] initWithFrame:CGRectMake(10, 70+64, 300, 30)];
_submitText.delegate=self;
_submitText.borderStyle = UITextBorderStyleRoundedRect;
_submitText.text = @"192.168.1.21";//這里是我測試的發(fā)送目標(biāo)的IP地址
[self.view addSubview:_submitText];
}
-(void)initSocket
{
//收發(fā)socket實(shí)例化
_recvSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[_recvSocket bindToPort:recvPort error:nil];
//在這里接收的套接字需要開啟一個接收消息的監(jiān)聽如下:
if (![_recvSocket beginReceiving:nil]) {
[_recvSocket close];
NSLog(@"Error starting server");
return;
}
_sendSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[_sendSocket bindToPort:sendPort error:nil];
}
-(void)buttonClicked:(UIButton*)button
{
if (button.tag==100){
[self connectUDPTest];
}else if(button.tag==101){
[self sendUDPTouched];
}
}
- (void)connectUDPTest{
}
- (void)sendUDPTouched
{
//向目標(biāo)IP發(fā)送消息
NSString *sengStr = [NSString stringWithFormat:@"%@-發(fā)來消息",_ipText.text];
[_sendSocket sendData:[sengStr dataUsingEncoding:NSUTF8StringEncoding] toHost:_ipText.text port:recvPort withTimeout:-1 tag:1];
NSLog(@"localPort = %hu", [_sendSocket localPort]);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
NSLog(@"Message didReceiveData :%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
操作效果截圖如下:
二.ARC的版本2:客戶端對服務(wù)器
1.新建兩個工程一個客戶端稠歉,一個模擬服務(wù)器掰担。首先上服務(wù)器
#define PORT 8008 //服務(wù)器端口設(shè)置
@import CocoaAsyncSocket;//導(dǎo)入頭文件
#*** pods導(dǎo)入方式:pod 'CocoaAsyncSocket' ***#
GCDAsyncUdpSocketDelegate 需要遵循的代理協(xié)議
GCDAsyncUdpSocket *serverSocket;//服務(wù)器socket
2.服務(wù)器socket實(shí)例化 在PORT端口監(jiān)聽數(shù)據(jù)
serverSocket=[[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[serverSocket bindToPort:PORT error:nil];
if (![serverSocket beginReceiving:nil]) {
[serverSocket close];
NSLog(@"Error starting server");
return;
}
3.GCDAsyncUdpSocket相關(guān)代理方法
// 網(wǎng)絡(luò)連接成功后 自動回調(diào)
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address
{
NSLog(@"已連接到用戶:ip:%@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
NSString *datastr=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// 將數(shù)據(jù)回寫給發(fā)送數(shù)據(jù)的用戶
NSLog(@"debug >>>> %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[sock sendData:[[NSString stringWithFormat:@"服務(wù)器收到客戶端消息返回%@",datastr] dataUsingEncoding:NSUTF8StringEncoding] toAddress:address withTimeout:-1 tag:300];
}
4客戶端相關(guān)
#define HOST @"192.168.1.108" //服務(wù)器地址
#define PORT 8008 //服務(wù)器端口
@import CocoaAsyncSocket;//導(dǎo)入頭文件
#*** pods導(dǎo)入方式:pod 'CocoaAsyncSocket' ***#
GCDAsyncUdpSocketDelegate 需要遵循的代理協(xié)議
GCDAsyncUdpSocket *_udpSocket;//客戶端socket
@property (strong, nonatomic) UITextField *ipText;//發(fā)送目標(biāo)的IP地址
GCDAsyncUdpSocket.h
#define HOST @"192.168.1.108"
#define PORT 8008
#import <UIKit/UIKit.h>
#import "GCDAsyncUdpSocket.h"
@interface UDPServerCommunicationViewController : UIViewController<GCDAsyncUdpSocketDelegate>
{
GCDAsyncUdpSocket *_udpSocket;
}
@property (strong, nonatomic) UITextField *ipText;
@end
GCDAsyncUdpSocket.m
#import "UDPServerCommunicationViewController.h"
@interface UDPServerCommunicationViewController ()
@end
@implementation UDPServerCommunicationViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
if (!_udpSocket)
{
_udpSocket=nil;
}
_udpSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSArray *nameArray=[NSArray arrayWithObjects:@"連接",@"發(fā)送",nil];
for (int i=0;i<[nameArray count];i++) {
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:[nameArray objectAtIndex:i] forState:UIControlStateNormal];
[button setFrame:CGRectMake(10+50*i, 30+64, 50, 30)];
button.tag=100+i;
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
_ipText=[[UITextField alloc] initWithFrame:CGRectMake(10, 70+64, 300, 30)];
_ipText.borderStyle = UITextBorderStyleRoundedRect;
_ipText.text = HOST;
[self.view addSubview:_ipText];
}
-(void)buttonClicked:(UIButton*)button
{
if (button.tag==100){
[self connectUDPTest];
}else if(button.tag==101){
[self sendUDPTouched];
}
}
-(void)connectUDPTest
{
NSError *error = nil;
if(![_udpSocket connectedHost]){
if (![_udpSocket connectToHost:HOST onPort:PORT error:&error]) {
if (error==nil){
NSLog(@"連接成功");
}else{
NSLog(@"連接失敗:%@",error);
}
}else{
NSLog(@"已經(jīng)連接");
}
}else{
NSLog(@"已經(jīng)連接:%@",[_udpSocket connectedHost]);
}
}
//客戶端發(fā)送本機(jī)IP地址給服務(wù)器
- (void)sendUDPTouched{
[_udpSocket sendData:[_ipText.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:1];
// [_udpSocket sendData:[_ipText.text dataUsingEncoding:NSUTF8StringEncoding] toHost:HOST port:PORT withTimeout:-1 tag:1];
NSLog(@"Udp Echo server started on port %hu", [_udpSocket localPort]);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address
{
NSError *error = nil;
NSLog(@"Message didConnectToAddress: %@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]);
[_udpSocket beginReceiving:&error];
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error
{
NSLog(@"Message didNotConnect: %@",error);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
NSLog(@"Message didNotSendDataWithTag: %@",error);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
NSLog(@"Message didReceiveData :%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
NSLog(@"Message 發(fā)送成功");
}
@end
操作效果截圖如下:
iOS-Socket-TCP篇
TCP篇這里把服務(wù)器模擬和客戶端點(diǎn)對點(diǎn)放在一起
圖解方式為:
一.(GCDAsyncSocket)ARC的版本
1.服務(wù)器
#import <UIKit/UIKit.h>
@import CocoaAsyncSocket;
@interface ServerViewController : UIViewController<GCDAsyncSocketDelegate,UITableViewDataSource,UITableViewDelegate>
{
GCDAsyncSocket *serverSocket;
UITableView *clientTableView;
NSMutableArray *socketArray;
}
@end
#import "ServerViewController.h"
@interface ServerViewController ()
@end
@implementation ServerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
clientTableView=[[UITableView alloc] initWithFrame:CGRectMake(0,100+64,Screen_Width,Screen_Height-164) style:UITableViewStylePlain];
clientTableView.delegate=self;
clientTableView.dataSource=self;
[self.view addSubview:clientTableView];
// 存儲連接到服務(wù)器的socket的數(shù)組
socketArray =[[NSMutableArray alloc] initWithCapacity:0];
// 服務(wù)器socket實(shí)例化 在0x1234端口監(jiān)聽數(shù)據(jù)
serverSocket=[[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[serverSocket acceptOnPort:0x1234 error:nil];
}
// 有新的socket向服務(wù)器鏈接自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
[socketArray addObject:newSocket];
[clientTableView reloadData];
// 如果下面的方法不寫 只能接收一次socket鏈接
[newSocket readDataWithTimeout:-1 tag:100];
}
// 網(wǎng)絡(luò)連接成功后 自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"已連接到用戶:ip:%@",host);
}
// 接收到了數(shù)據(jù) 自動回調(diào) sock客戶端
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *message=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"收到%@發(fā)來的消息:%@",[sock connectedHost],message);
// 相當(dāng)與向服務(wù)起索取 在線用戶數(shù)據(jù)
// 將連上服務(wù)器的所有ip地址 組成一個字符串 將字符串回寫到客戶端
if ([message isEqualToString:@"GetClientList"]) {
NSMutableString *clientList=[[NSMutableString alloc] initWithCapacity:0];
int i=0;
// 每一個客戶端連接服務(wù)器成功后 socketArray保存客戶端的套接字
// [newSocket connectedHost] 獲取套接字對應(yīng)的IP地址
for (GCDAsyncSocket *newSocket in socketArray) {
// 以字符串形式分割ip地址 192..,192...,
if (i!=0) {
[clientList appendFormat:@",%@",[newSocket connectedHost]];
}
else{
[clientList appendFormat:@"%@",[newSocket connectedHost]];
}
i++;
}
// 將服務(wù)端所有的ip連接成一個字符串對象
NSData *newData=[clientList dataUsingEncoding:NSUTF8StringEncoding];
// 將在線的所有用戶 以字符串的形式一次性發(fā)給客戶端
// 哪個客戶端發(fā)起數(shù)據(jù)請求sock就表示誰
[sock writeData:newData withTimeout:-1 tag:300];
}
else{
// 將數(shù)據(jù)回寫給發(fā)送數(shù)據(jù)的用戶
NSLog(@"debug >>>> %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[sock writeData:data withTimeout:-1 tag:300];
}
// 繼續(xù)讀取socket數(shù)據(jù)
[sock readDataWithTimeout:-1 tag:200];
}
/*重連
實(shí)現(xiàn)代理方法
-(void)onSocketDidDisconnect:(GCDAsyncSocket *)sock
{
NSLog(@"sorry the connect is failure %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服務(wù)器掉線怒炸,重連
[self socketConnectHost];
}
else if (sock.userData == SocketOfflineByUser) {
// 如果由用戶斷開带饱,不進(jìn)行重連
return;
}
}*/
// 連接斷開時 服務(wù)器自動回調(diào)
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock
{
[socketArray removeObject:sock];
[clientTableView reloadData];
}
// 向用戶發(fā)出的消息 自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"向用戶%@發(fā)出消息",[sock connectedHost]);
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [socketArray count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellName=@"CellName";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellName];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellName];
}
GCDAsyncSocket *socket=[socketArray objectAtIndex:indexPath.row];
// 根據(jù)連接服務(wù)端套接字socket對象 獲取對應(yīng)的客戶端IP地址
cell.textLabel.text=[NSString stringWithFormat:@"用戶:%@",[socket connectedHost]];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
2.客戶端
#import <UIKit/UIKit.h>
@import CocoaAsyncSocket;
@interface ClientViewController : UIViewController<GCDAsyncSocketDelegate,UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
{
GCDAsyncSocket *serverSocket;//服務(wù)器socket
GCDAsyncSocket *listenSocket;//客戶端自身socket(接收消息)
GCDAsyncSocket *clientSocket;//客戶端發(fā)送socket(發(fā)送消息)
UITableView *clientTableView;
NSMutableArray *clientArray;
UITextField* messageTextField;
NSString *ipCopy;
}
#import "ServerViewController.h"
#import "ClientViewController.h"
@interface ServerViewController ()
@end
@implementation ServerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
clientTableView=[[UITableView alloc] initWithFrame:CGRectMake(0,100+64,Screen_Width,Screen_Height-164) style:UITableViewStylePlain];
clientTableView.delegate=self;
clientTableView.dataSource=self;
[self.view addSubview:clientTableView];
socketArray =[[NSMutableArray alloc] initWithCapacity:0];
// 服務(wù)器socket實(shí)例化 在0x1234端口監(jiān)聽數(shù)據(jù)
serverSocket=[[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
[serverSocket acceptOnPort:PORT error:nil];
}
// 有新的socket向服務(wù)器鏈接自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
[socketArray addObject:newSocket];
[clientTableView reloadData];
// 如果下面的方法不寫 只能接收一次socket鏈接
[newSocket readDataWithTimeout:-1 tag:100];
}
// 網(wǎng)絡(luò)連接成功后 自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"已連接到用戶:ip:%@",host);
}
// 接收到了數(shù)據(jù) 自動回調(diào) sock客戶端
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *message=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"收到%@發(fā)來的消息:%@",[sock connectedHost],message);
// 相當(dāng)與向服務(wù)起索取 在線用戶數(shù)據(jù)
// 將連上服務(wù)器的所有ip地址 組成一個字符串 將字符串回寫到客戶端
if ([message isEqualToString:@"GetClientList"]) {
NSMutableString *clientList=[[NSMutableString alloc] initWithCapacity:0];
int i=0;
// 每一個客戶端連接服務(wù)器成功后 socketArray保存客戶端的套接字
// [newSocket connectedHost] 獲取套接字對應(yīng)的IP地址
for (GCDAsyncSocket *newSocket in socketArray) {
// 以字符串形式分割ip地址 192..,192...,
if (i!=0) {
[clientList appendFormat:@",%@",[newSocket connectedHost]];
}
else{
[clientList appendFormat:@"%@",[newSocket connectedHost]];
}
i++;
}
// 將服務(wù)端所有的ip連接成一個字符串對象
NSData *newData=[clientList dataUsingEncoding:NSUTF8StringEncoding];
// 將在線的所有用戶 以字符串的形式一次性發(fā)給客戶端
// 哪個客戶端發(fā)起數(shù)據(jù)請求sock就表示誰
[sock writeData:newData withTimeout:-1 tag:300];
}
else{
// 將數(shù)據(jù)回寫給發(fā)送數(shù)據(jù)的用戶
NSLog(@"debug >>>> %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[sock writeData:data withTimeout:-1 tag:300];
}
// 繼續(xù)讀取socket數(shù)據(jù)
[sock readDataWithTimeout:-1 tag:200];
}
/*重連
實(shí)現(xiàn)代理方法
-(void)onSocketDidDisconnect:(GCDAsyncSocket *)sock
{
NSLog(@"sorry the connect is failure %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服務(wù)器掉線纠炮,重連
[self socketConnectHost];
}
else if (sock.userData == SocketOfflineByUser) {
// 如果由用戶斷開灯蝴,不進(jìn)行重連
return;
}
}*/
// 連接斷開時 服務(wù)器自動回調(diào)
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock
{
[socketArray removeObject:sock];
[clientTableView reloadData];
}
// 向用戶發(fā)出的消息 自動回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"向用戶%@發(fā)出消息",[sock connectedHost]);
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [socketArray count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellName=@"CellName";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellName];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellName];
}
GCDAsyncSocket *socket=[socketArray objectAtIndex:indexPath.row];
// 根據(jù)連接服務(wù)端套接字socket對象 獲取對應(yīng)的客戶端IP地址
cell.textLabel.text=[NSString stringWithFormat:@"用戶:%@",[socket connectedHost]];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
操作效果截圖如下:
二.(AsyncSocket)非ARC的版本
(AsyncSocket)非ARC的版本1.服務(wù)器
#import <UIKit/UIKit.h>
#import "AsyncSocket.h"
@interface ServerViewController : UIViewController<AsyncSocketDelegate,UITableViewDataSource,UITableViewDelegate>
{
AsyncSocket *serverSocket;
UITableView *clientTableView;
NSMutableArray *clientArray;
NSMutableArray *socketArray;
}
@end
#import "ServerViewController.h"
@interface ServerViewController ()
@end
@implementation ServerViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
clientTableView=[[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
clientTableView.delegate=self;
clientTableView.dataSource=self;
[self.view addSubview:clientTableView];
clientArray=[[NSMutableArray alloc] initWithCapacity:0];
socketArray =[[NSMutableArray alloc] initWithCapacity:0];
// 服務(wù)器socket實(shí)例化 在0x1234端口監(jiān)聽數(shù)據(jù)
serverSocket=[[AsyncSocket alloc] init];
serverSocket.delegate=self;
[serverSocket acceptOnPort:0x1234 error:nil];
}
// 有新的socket向服務(wù)器鏈接自動回調(diào)
-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
[socketArray addObject:newSocket];
[clientTableView reloadData];
// 如果下面的方法不寫 只能接收一次socket鏈接
[newSocket readDataWithTimeout:-1 tag:100];
}
// 網(wǎng)絡(luò)連接成功后 自動回調(diào)
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"已連接到用戶:ip:%@",host);
}
// 接收到了數(shù)據(jù) 自動回調(diào) sock客戶端
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *message=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"收到%@發(fā)來的消息:%@",[sock connectedHost],message);
// 相當(dāng)與向服務(wù)起索取 在線用戶數(shù)據(jù)
// 將連上服務(wù)器的所有ip地址 組成一個字符串 將字符串回寫到客戶端
if ([message isEqualToString:@"GetClientList"]) {
NSMutableString *clientList=[[NSMutableString alloc] initWithCapacity:0];
int i=0;
for (AsyncSocket *newSocket in socketArray) {
// 以字符串形式分割ip地址 192..,192...,
if (i!=0) {
[clientList appendFormat:@",%@",[newSocket connectedHost]];
}
else{
[clientList appendFormat:@"%@",[newSocket connectedHost]];
}
i++;
}
// 將服務(wù)端所有的ip連接成一個字符串對象
NSData *newData=[clientList dataUsingEncoding:NSUTF8StringEncoding];
// 將在線的所有用戶 以字符串的形式一次性發(fā)給客戶端
// 哪個客戶端發(fā)起數(shù)據(jù)請求sock就表示誰
[sock writeData:newData withTimeout:-1 tag:300];
}
else{
// 將數(shù)據(jù)回寫給發(fā)送數(shù)據(jù)的用戶
NSLog(@"debug >>>> %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[sock writeData:data withTimeout:-1 tag:300];
}
// 繼續(xù)讀取socket數(shù)據(jù)
[sock readDataWithTimeout:-1 tag:200];
}
// 連接斷開時 服務(wù)器自動回調(diào)
-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
[socketArray removeObject:sock];
[clientTableView reloadData];
}
// 向用戶發(fā)出的消息 自動回調(diào)
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"向用戶%@發(fā)出消息",[sock connectedHost]);
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [socketArray count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellName=@"CellName";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellName];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellName];
}
AsyncSocket *socket=[socketArray objectAtIndex:indexPath.row];
// 根據(jù)連接服務(wù)端套接字socket對象 獲取對應(yīng)的客戶端IP地址
cell.textLabel.text=[NSString stringWithFormat:@"用戶:%@",[socket connectedHost]];
return cell;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
1.(AsyncSocket)非ARC的版本客戶端
#import <UIKit/UIKit.h>
#import "AsyncSocket.h"
@interface ClientViewController : UIViewController<AsyncSocketDelegate,UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
{
AsyncSocket *serverSocket;
AsyncSocket *listenSocket;
AsyncSocket *clientSocket;
UITableView *clientTableView;
NSMutableArray *clientArray;
UITextField* messageTextField;
}
@end
#import "ClientViewController.h"
@interface ClientViewController ()
@end
@implementation ClientViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// A(監(jiān)聽收對方發(fā)來的數(shù)據(jù)) server(連接服務(wù)器) B(對方)
// 服務(wù)器socket
serverSocket =[[AsyncSocket alloc] init];
serverSocket.delegate=self;
// 本身
listenSocket=[[AsyncSocket alloc] initWithDelegate:self];
[listenSocket acceptOnPort:0x1235 error:nil];
// 點(diǎn)對點(diǎn)通訊時 對方的socket
clientSocket=[[AsyncSocket alloc] initWithDelegate:self];
NSArray *nameArray=[NSArray arrayWithObjects:@"連接",@"斷開",@"在線用戶", nil];
for (int i=0;i<[nameArray count];i++) {
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:[nameArray objectAtIndex:i] forState:UIControlStateNormal];
[button setFrame:CGRectMake(10+50*i, 30, 50, 30)];
button.tag=100+i;
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
clientTableView=[[UITableView alloc] initWithFrame:CGRectMake(0, 80, 320,380) style:UITableViewStylePlain];
clientTableView.delegate=self;
clientTableView.dataSource=self;
[self.view addSubview:clientTableView];
clientArray=[[NSMutableArray alloc] initWithCapacity:0];
messageTextField=[[UITextField alloc] initWithFrame:CGRectMake(10, 50, 300, 30)];
messageTextField.delegate=self;
messageTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:messageTextField];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
// 發(fā)數(shù)據(jù) 結(jié)束編輯 就是鍵盤隱藏的時候 自動調(diào)用
-(void)textFieldDidEndEditing:(UITextField *)textField
{
if (clientSocket && [clientSocket isConnected]) {
NSData *data=[textField.text dataUsingEncoding:NSUTF8StringEncoding];
// 向socket寫數(shù)據(jù)
[clientSocket writeData:data withTimeout:-1 tag:100];
//[serverSocket writeData:data withTimeout:-1 tag:200];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [clientArray count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellName=@"CellName";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellName];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellName];
}
cell.textLabel.text=[clientArray objectAtIndex:indexPath.row];
return cell;
}
-(void)buttonClicked:(UIButton*)button
{
if (button.tag==100)
{
// 連接服務(wù)器
if (![serverSocket isConnected])
{
//[serverSocket disconnect];
// 指定 ip 指定端口 發(fā)起一個TCP連接
[serverSocket connectToHost:@"192.168.1.108" onPort:0x1234 error:nil];
// 向服務(wù)器寫數(shù)據(jù)
// [serverSocket writeData:<#(NSData *)#> withTimeout:<#(NSTimeInterval)#> tag:<#(long)#>]
}
else
{
NSLog(@"已經(jīng)和服務(wù)器連接");
}
}
// 斷開與服務(wù)器連接
else if(button.tag==101)
{
// 斷開TCP連接
[serverSocket disconnect];
}
// 獲取在線用戶
else if(button.tag==102)
{
NSString *message=@"GetClientList";
NSData *data=[message dataUsingEncoding:NSUTF8StringEncoding];
// 向服務(wù)器獲取在線用戶信息
// 向服務(wù)端寫字符串 GetClientList
[serverSocket writeData:data withTimeout:-1 tag:400];
}
}
// 接收到了一個新的socket連接 自動回調(diào)
// 接收到了新的連接 那么釋放老的連接
-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
if (sock==listenSocket) {
NSLog(@"收到用戶%@的連接請求",[newSocket connectedHost]);
if (clientSocket && [clientSocket isConnected]) {
[clientSocket disconnect];
[clientSocket release];
}
// 保存發(fā)起連接的客戶端socket
clientSocket=[newSocket retain];
}
}
// 寫數(shù)據(jù)成功 自動回調(diào)
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// 獲取用戶列表
if (sock==serverSocket) {
NSLog(@"向服務(wù)器%@發(fā)送消息成功",[sock connectedHost]);
}
// 客戶端與客戶端通訊
else if(sock==clientSocket){
NSLog(@"向客戶%@發(fā)送消息成功",[sock connectedHost]);
}
// 繼續(xù)監(jiān)聽
[sock readDataWithTimeout:-1 tag:500];
}
// 成功連接后自動回調(diào)
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
[sock readDataWithTimeout:-1 tag:200];
NSLog(@"已經(jīng)連接到服務(wù)器:%@",host);
}
// 客戶端接收到了數(shù)據(jù)
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// 如果時服務(wù)器給的消息 必然是在線用戶的消息
if (sock==serverSocket) {
NSString *message=[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
// 將字符串以","分割 到數(shù)組中
// 分割出IP地址
NSArray *array=[message componentsSeparatedByString:@","];
[clientArray removeAllObjects];
[clientArray addObjectsFromArray:array];
[clientTableView reloadData];
NSLog(@"在線用戶列表:%@",clientArray);
}
// 點(diǎn)對點(diǎn)通訊
else{
NSString *message=[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSLog(@"收到客戶%@的消息:%@",[sock connectedHost],message);
}
// 繼續(xù)監(jiān)聽
[sock readDataWithTimeout:-1 tag:100];
}
// 點(diǎn)擊一行時 向該行對應(yīng)的ip地址發(fā)起連接
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *ip=[clientArray objectAtIndex:indexPath.row];
if (clientSocket ) {
// 如果之前連接上了一個好友 那么先斷開
if ([clientSocket isConnected]) {
[clientSocket disconnect];
}
// 向TableViewCell上指定ip發(fā)起TCP連接
[clientSocket connectToHost:ip onPort:0x1235 error:nil];
// clientSocket已經(jīng)指向了好友 如果需要和好友發(fā)消息
NSData *data=[@"didSelectRowAtIndexPath" dataUsingEncoding:NSUTF8StringEncoding];
[clientSocket writeData:data withTimeout:-1 tag:100];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
操作效果截圖如下:和ARC一樣
1.GitHub地址:GCD ARC版本 UDP&TCP demo
https://github.com/Yjunjie/Socket-GCD-TCP-UDPdemo