WIFI通訊客戶端搭建
- 客戶的職責主要做三件事,一:連接服務端 二:接收來自服務端的數據 三:給服務端發送數據
- [1.0-準備工作]
- [1.1-客戶端連接服務端]
- [1.2-客戶端接收和發送數據到服務端]
- [1.3-完整代碼及示例演示]
1.0-準備工作
- 筆者搭建了一個簡單的界面,主要功能就是客戶端連接服務端監聽的網絡,連接成功之后可以給服務端發送數據
1.1-客戶端連接服務端
- 1.創建客戶端Socket
-
2.客戶端連接服務端socket
- socket本質就是ip地址加端口號,所以客戶端連接的也是ip地址加端口號,只不過這一個ip地址是服務端在局域網中的ip地址(上一小節獲?。?,端口號也是服務端所監聽的端口號(如果與服務端的ip地址和監聽的端口號不一致,客戶端是無法連接的,因為這一個i地址的電腦的端口號沒有被監聽)
//客戶端開始連接
- (IBAction)wifiButtonClik:(UIButton *)sender {
//1.創建客戶端socket
//在socket通訊中,無論是客戶端還是服務端,任何對象都是socket,類似于萬物皆NSObject
if (!self.clientSocket) {
self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSLog(@"%@",self.clientSocket.localHost);
//2.連接服務端
//注意:此處有兩個重點 1.這里的ip地址一定要是同一個局域網服務端的ip地址,端口號也要與服務端連接的端口號一致 2.實際開發中,一般服務端的ip地址和所監聽的端口號都會在wifit通信協議中注明,這里只是筆者為了掩飾,所以隨便寫了一個端口號1234,而這里的ip地址也是筆者為了掩飾給mac電腦設置了一個固定ip地址
[self.clientSocket connectToHost:@"192.168.0.102" onPort:1234 error:nil];
}
1.2-客戶端接收和發送數據到服務端
***1.客戶端連接成功之后,開始讀取服務端的數據
2.客戶端將接收到服務端的數據添加在數組,用于顯示(實際開發中可能需要處理其他邏輯,具體看需求)
3.客戶端發送數據到服務端(實際開發中數據格式由硬件工程師來定義)
#pragma mark- GCDAsyncSocketDelegate
//客戶端連接服務端成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
//1.將開始連接按鈕變為已連接
[self.clientButton setTitle:@"連接成功" forState:UIControlStateNormal];
//2.發送數據按鈕開啟交互
self.senMsgButton.enabled = YES;
//3.客戶端開始讀取服務端的數據
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
//客戶端接收數據成功
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客戶端接發送數據:%@",str);
//0.添加到數據源
[self.tableArr addObject:data];
//1.刷新界面
[self.tableView reloadData];
//2.繼續讀取數據(否則只能讀取一次)
[sock readDataWithTimeout:-1 tag:0];
}
//客戶端發送數據成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"客戶端發送數據");
//刷新數據
[self.tableView reloadData];
}
#pragma mark -UITextFieldDelegate 發送數據
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
//1.發送數據 具體的數據格式會由硬件工程師定義,示例這里使用冒號:將我的手機名稱和消息分開
NSString *str = [NSString stringWithFormat:@"%@:%@",[UIDevice currentDevice].name,textField.text];
//2.發送數據 第一個參數:二進制數據 第二個參數:超時等待 -1為永久等待 tag:消息標簽 沒啥用
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:1];
//3添加到數組用于顯示
[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.
}
//客戶端開始連接
- (IBAction)wifiButtonClik:(UIButton *)sender {
//1.創建客戶端socket
//在socket通訊中,無論是客戶端還是服務端,任何對象都是socket,類似于萬物皆NSObject
if (!self.clientSocket) {
self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSLog(@"%@",self.clientSocket.localHost);
//2.連接服務端
//注意:此處有兩個重點 1.這里的ip地址一定要是同一個局域網服務端的ip地址,端口號也要與服務端連接的端口號一致 2.實際開發中,一般服務端的ip地址和所監聽的端口號都會在wifit通信協議中注明,這里只是筆者為了掩飾,所以隨便寫了一個端口號1234,而這里的ip地址也是筆者為了掩飾給mac電腦設置了一個固定ip地址
[self.clientSocket connectToHost:@"192.168.0.102" onPort:1234 error:nil];
}
//客戶端發送數據
- (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
//客戶端連接服務端成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
//1.將開始連接按鈕變為已連接
[self.clientButton setTitle:@"連接成功" forState:UIControlStateNormal];
//2.發送數據按鈕開啟交互
self.senMsgButton.enabled = YES;
//3.客戶端開始讀取服務端的數據
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
//客戶端接收數據成功
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"客戶端接發送數據:%@",str);
//0.添加到數據源
[self.tableArr addObject:data];
//1.刷新界面
[self.tableView reloadData];
//2.繼續讀取數據(否則只能讀取一次)
[sock readDataWithTimeout:-1 tag:0];
}
//客戶端發送數據成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"客戶端發送數據");
//刷新數據
[self.tableView reloadData];
}
#pragma mark -UITextFieldDelegate 發送數據
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
//1.發送數據 具體的數據格式會由硬件工程師定義,示例這里使用冒號:將我的手機名稱和消息分開
NSString *str = [NSString stringWithFormat:@"%@:%@",[UIDevice currentDevice].name,textField.text];
//2.發送數據 第一個參數:二進制數據 第二個參數:超時等待 -1為永久等待 tag:消息標簽 沒啥用
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:1];
//3添加到數組用于顯示
[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];
//讀取數據
NSData *data = self.tableArr[indexPath.row];
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray *arr = [str componentsSeparatedByString:@":"];
//顯示數據
nameLabel.text = [NSString stringWithFormat:@"設備名稱:%@",arr[0]];
msgLabel.text = [NSString stringWithFormat:@" 數據:%@",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