WIFI通訊客戶端搭建
- 客戶的職責(zé)主要做三件事遮晚,一:連接服務(wù)端 二:接收來(lái)自服務(wù)端的數(shù)據(jù) 三:給服務(wù)端發(fā)送數(shù)據(jù)
- [1.0-準(zhǔn)備工作]
- [1.1-客戶端連接服務(wù)端]
- [1.2-客戶端接收和發(fā)送數(shù)據(jù)到服務(wù)端]
- [1.3-完整代碼及示例演示]
1.0-準(zhǔn)備工作
- 筆者搭建了一個(gè)簡(jiǎn)單的界面,主要功能就是客戶端連接服務(wù)端監(jiān)聽(tīng)的網(wǎng)絡(luò)三娩,連接成功之后可以給服務(wù)端發(fā)送數(shù)據(jù)
1.1-客戶端連接服務(wù)端
- 1.創(chuàng)建客戶端Socket
-
2.客戶端連接服務(wù)端socket
- socket本質(zhì)就是ip地址加端口號(hào)鸿脓,所以客戶端連接的也是ip地址加端口號(hào)抑钟,只不過(guò)這一個(gè)ip地址是服務(wù)端在局域網(wǎng)中的ip地址(上一小節(jié)獲取)野哭,端口號(hào)也是服務(wù)端所監(jiān)聽(tīng)的端口號(hào)(如果與服務(wù)端的ip地址和監(jiān)聽(tīng)的端口號(hào)不一致在塔,客戶端是無(wú)法連接的,因?yàn)檫@一個(gè)i地址的電腦的端口號(hào)沒(méi)有被監(jiān)聽(tīng))
//客戶端開(kāi)始連接
- (IBAction)wifiButtonClik:(UIButton *)sender {
//1.創(chuàng)建客戶端socket
//在socket通訊中拨黔,無(wú)論是客戶端還是服務(wù)端蛔溃,任何對(duì)象都是socket,類似于萬(wàn)物皆NSObject
if (!self.clientSocket) {
self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSLog(@"%@",self.clientSocket.localHost);
//2.連接服務(wù)端
//注意:此處有兩個(gè)重點(diǎn) 1.這里的ip地址一定要是同一個(gè)局域網(wǎng)服務(wù)端的ip地址篱蝇,端口號(hào)也要與服務(wù)端連接的端口號(hào)一致 2.實(shí)際開(kāi)發(fā)中贺待,一般服務(wù)端的ip地址和所監(jiān)聽(tīng)的端口號(hào)都會(huì)在wifit通信協(xié)議中注明,這里只是筆者為了掩飾零截,所以隨便寫(xiě)了一個(gè)端口號(hào)1234麸塞,而這里的ip地址也是筆者為了掩飾給mac電腦設(shè)置了一個(gè)固定ip地址
[self.clientSocket connectToHost:@"192.168.0.102" onPort:1234 error:nil];
}
1.2-客戶端接收和發(fā)送數(shù)據(jù)到服務(wù)端
***1.客戶端連接成功之后,開(kāi)始讀取服務(wù)端的數(shù)據(jù)
2.客戶端將接收到服務(wù)端的數(shù)據(jù)添加在數(shù)組涧衙,用于顯示(實(shí)際開(kāi)發(fā)中可能需要處理其他邏輯哪工,具體看需求)
3.客戶端發(fā)送數(shù)據(jù)到服務(wù)端(實(shí)際開(kāi)發(fā)中數(shù)據(jù)格式由硬件工程師來(lái)定義)
#pragma mark- GCDAsyncSocketDelegate
//客戶端連接服務(wù)端成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
//1.將開(kāi)始連接按鈕變?yōu)橐堰B接
[self.clientButton setTitle:@"連接成功" forState:UIControlStateNormal];
//2.發(fā)送數(shù)據(jù)按鈕開(kāi)啟交互
self.senMsgButton.enabled = YES;
//3.客戶端開(kāi)始讀取服務(wù)端的數(shù)據(jù)
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
//客戶端接收數(shù)據(jù)成功
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客戶端接發(fā)送數(shù)據(jù):%@",str);
//0.添加到數(shù)據(jù)源
[self.tableArr addObject:data];
//1.刷新界面
[self.tableView reloadData];
//2.繼續(xù)讀取數(shù)據(jù)(否則只能讀取一次)
[sock readDataWithTimeout:-1 tag:0];
}
//客戶端發(fā)送數(shù)據(jù)成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"客戶端發(fā)送數(shù)據(jù)");
//刷新數(shù)據(jù)
[self.tableView reloadData];
}
#pragma mark -UITextFieldDelegate 發(fā)送數(shù)據(jù)
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
//1.發(fā)送數(shù)據(jù) 具體的數(shù)據(jù)格式會(huì)由硬件工程師定義,示例這里使用冒號(hào):將我的手機(jī)名稱和消息分開(kāi)
NSString *str = [NSString stringWithFormat:@"%@:%@",[UIDevice currentDevice].name,textField.text];
//2.發(fā)送數(shù)據(jù) 第一個(gè)參數(shù):二進(jìn)制數(shù)據(jù) 第二個(gè)參數(shù):超時(shí)等待 -1為永久等待 tag:消息標(biāo)簽 沒(méi)啥用
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:1];
//3添加到數(shù)組用于顯示
[self.tableArr addObject:[str dataUsingEncoding:NSUTF8StringEncoding]];
textField.text = nil;
return YES;
}
1.3-完整代碼及示例演示
#import "ClientViewController.h"
#import "GCDAsyncSocket.h"
#import "WIFITools.h"
@interface ClientViewController ()<GCDAsyncSocketDelegate,UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UILabel *wifiNameLabel;
@property (weak, nonatomic) IBOutlet UILabel *ipAddressLabel;
@property (weak, nonatomic) IBOutlet UIButton *senMsgButton;
@property (weak, nonatomic) IBOutlet UIButton *clientButton;
@property(nonatomic,strong)UITextField *textField;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
//存放客戶端的消息用于顯示
@property(nonatomic,strong)NSMutableArray <NSData *>*tableArr;
//
//客戶端socket
@property(nonatomic,strong)GCDAsyncSocket *clientSocket;
@end
@implementation ClientViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.wifiNameLabel.text = [NSString stringWithFormat:@"wifi名稱:%@",[WIFITools currentWifiSSID]];
self.ipAddressLabel.text = [NSString stringWithFormat:@"ip地址:%@",[WIFITools localWiFiIPAddress]];
self.tableArr = [NSMutableArray array];
// Do any additional setup after loading the view.
}
//客戶端開(kāi)始連接
- (IBAction)wifiButtonClik:(UIButton *)sender {
//1.創(chuàng)建客戶端socket
//在socket通訊中弧哎,無(wú)論是客戶端還是服務(wù)端雁比,任何對(duì)象都是socket,類似于萬(wàn)物皆NSObject
if (!self.clientSocket) {
self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSLog(@"%@",self.clientSocket.localHost);
//2.連接服務(wù)端
//注意:此處有兩個(gè)重點(diǎn) 1.這里的ip地址一定要是同一個(gè)局域網(wǎng)服務(wù)端的ip地址撤嫩,端口號(hào)也要與服務(wù)端連接的端口號(hào)一致 2.實(shí)際開(kāi)發(fā)中偎捎,一般服務(wù)端的ip地址和所監(jiān)聽(tīng)的端口號(hào)都會(huì)在wifit通信協(xié)議中注明,這里只是筆者為了掩飾,所以隨便寫(xiě)了一個(gè)端口號(hào)1234茴她,而這里的ip地址也是筆者為了掩飾給mac電腦設(shè)置了一個(gè)固定ip地址
[self.clientSocket connectToHost:@"192.168.0.102" onPort:1234 error:nil];
}
//客戶端發(fā)送數(shù)據(jù)
- (IBAction)sendMsgButton:(UIButton*)sender {
if (!self.textField) {
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 40)];
self.textField.delegate = self;
self.textField.returnKeyType = UIReturnKeySend;
[self.view addSubview:self.textField];
}
self.textField.hidden = NO;
[self.textField becomeFirstResponder];
}
#pragma mark- GCDAsyncSocketDelegate
//客戶端連接服務(wù)端成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
//1.將開(kāi)始連接按鈕變?yōu)橐堰B接
[self.clientButton setTitle:@"連接成功" forState:UIControlStateNormal];
//2.發(fā)送數(shù)據(jù)按鈕開(kāi)啟交互
self.senMsgButton.enabled = YES;
//3.客戶端開(kāi)始讀取服務(wù)端的數(shù)據(jù)
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
//客戶端接收數(shù)據(jù)成功
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客戶端接發(fā)送數(shù)據(jù):%@",str);
//0.添加到數(shù)據(jù)源
[self.tableArr addObject:data];
//1.刷新界面
[self.tableView reloadData];
//2.繼續(xù)讀取數(shù)據(jù)(否則只能讀取一次)
[sock readDataWithTimeout:-1 tag:0];
}
//客戶端發(fā)送數(shù)據(jù)成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"客戶端發(fā)送數(shù)據(jù)");
//刷新數(shù)據(jù)
[self.tableView reloadData];
}
#pragma mark -UITextFieldDelegate 發(fā)送數(shù)據(jù)
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
//1.發(fā)送數(shù)據(jù) 具體的數(shù)據(jù)格式會(huì)由硬件工程師定義蜕径,示例這里使用冒號(hào):將我的手機(jī)名稱和消息分開(kāi)
NSString *str = [NSString stringWithFormat:@"%@:%@",[UIDevice currentDevice].name,textField.text];
//2.發(fā)送數(shù)據(jù) 第一個(gè)參數(shù):二進(jìn)制數(shù)據(jù) 第二個(gè)參數(shù):超時(shí)等待 -1為永久等待 tag:消息標(biāo)簽 沒(méi)啥用
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:1];
//3添加到數(shù)組用于顯示
[self.tableArr addObject:[str dataUsingEncoding:NSUTF8StringEncoding]];
textField.text = nil;
return YES;
}
#pragma mark -UITableViewDelegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tableArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"clientCell"];
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
UILabel *msgLabel = (UILabel *)[cell.contentView viewWithTag:2];
//讀取數(shù)據(jù)
NSData *data = self.tableArr[indexPath.row];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *arr = [str componentsSeparatedByString:@":"];
//顯示數(shù)據(jù)
nameLabel.text = [NSString stringWithFormat:@"設(shè)備名稱:%@",arr[0]];
msgLabel.text = [NSString stringWithFormat:@" 數(shù)據(jù):%@",arr[1]];
return cell;
}
- (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