欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS 使用 socket 實(shí)現(xiàn)即時(shí)通信示例(非第三方庫(kù))

 更新時(shí)間:2017年02月15日 16:09:34   作者:gwk_ios  
這篇文章主要介紹了iOS 使用 socket 即時(shí)通信示例(非第三方庫(kù))的資料,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。

其實(shí)寫這個(gè)socket一開始我是拒絕的。

因?yàn)榇蠹覍W(xué)C 語(yǔ)言和linux基礎(chǔ)時(shí)肯定都有接觸,客戶端和服務(wù)端的通信也都了解過(guò),加上現(xiàn)在很多開放的第三方庫(kù)都不需要我們來(lái)操作底層的通信。

但是!還是想寫。底層的東西最好了解下。

效果

由于5M的上傳限制GIF可能看不清 我再截兩張圖吧

服務(wù)器

客戶端A

客戶端B

模型圖

分析

由上圖可以了解到服務(wù)器和客戶端需要做哪些工作

服務(wù)器

抽象一點(diǎn)分為:

1.創(chuàng)建線程等待接收客戶端的連接

2.接收并解析客戶端發(fā)來(lái)的消息

3.給客戶端發(fā)送消息

具體一點(diǎn):

1.創(chuàng)建socket. 綁定端口.開始監(jiān)聽.

2.創(chuàng)建線程.等待接收客戶端連接.

3.接收客戶端發(fā)來(lái)的消息

4.解析消息內(nèi)容

a.設(shè)置用戶名

b.發(fā)送消息給指定客戶端

客戶端

抽象一點(diǎn)分為:

1.連接服務(wù)器

2.給服務(wù)器發(fā)送消息

3.接收服務(wù)器消息

4.解析消息內(nèi)容

具體一點(diǎn):

1.創(chuàng)建socket.綁定端口.連接服務(wù)器

2.發(fā)送消息

a.設(shè)置用戶名

b.給指定用戶發(fā)消息:按服務(wù)器格式拼接字符串

3.接收消息

a.普通消息

b.用戶列表:保存至用戶列表

UI方面

服務(wù)器:其實(shí)不用什么UI放個(gè)控件展示下日志就是了

客戶端:比較簡(jiǎn)單,一個(gè)俗套聊天室的界面,直接storyboard里拖拖控件設(shè)置約束了

DEMO而已別太當(dāng)真

代碼部分

服務(wù)器

要使用scoket需要引用這三個(gè)頭文件

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

只有一個(gè)model,用來(lái)綁定用戶名和socket

@interface ClientModel : NSObject
@property(nonatomic,assign)int clientSocket;
@property(nonatomic,copy)NSString *clientName;
@end

只有一個(gè)文件全給你

#import "ViewController.h"

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#import "ClientModel.h"
static int const kMaxConnectCount = 5;

@interface ViewController()
@property (weak) IBOutlet NSTextField *textField;
//@property (nonatomic,assign)int client_socket; //客戶端socket
@property (unsafe_unretained) IBOutlet NSTextView *textView;
 @property (nonatomic,strong)NSMutableArray *clientArray;
 @property (nonatomic,strong)NSMutableArray *clientNameArray;
@end

@implementation ViewController

- (NSMutableArray *)clientArray {
 if (!_clientArray) {
  _clientArray = [NSMutableArray array];
 }
 return _clientArray;
}
- (NSMutableArray *)clientNameArray {
 if (!_clientNameArray) {
  _clientNameArray = [NSMutableArray array];
 }
 return _clientNameArray;
}

- (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view.
 //創(chuàng)建socket
 int server_socket = socket(AF_INET, SOCK_STREAM, 0);
 if (server_socket == -1) {
  NSLog(@"創(chuàng)建失敗");
  [self showLogsWithString:@"socket創(chuàng)建失敗"];

 }else{
  //綁定地址和端口
  struct sockaddr_in server_addr;
  server_addr.sin_len = sizeof(struct sockaddr_in);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(1234);
  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  bzero(&(server_addr.sin_zero), 8);

  int bind_result = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if (bind_result == -1) {
   NSLog(@"綁定端口失敗");
   [self showLogsWithString:@"綁定端口失敗"];

  }else{
   if (listen(server_socket, kMaxConnectCount)==-1) {
    NSLog(@"監(jiān)聽失敗");
    [self showLogsWithString:@"監(jiān)聽失敗"];

   }else{
    for (int i = 0; i < kMaxConnectCount; i++) {
     //接受客戶端的鏈接
     [self acceptClientWithServerSocket:server_socket];
    }
   }
  }
 }
}


- (void)setRepresentedObject:(id)representedObject {
 [super setRepresentedObject:representedObject];

 // Update the view, if already loaded.
}

//創(chuàng)建線程接受客戶端
-(void)acceptClientWithServerSocket:(int)server_socket{
 struct sockaddr_in client_address;
 socklen_t address_len;
 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 dispatch_async(queue, ^{
  //創(chuàng)建新的socket
  while (1) {
   int client_socket = accept(server_socket, (struct sockaddr*)&client_address,&address_len );
   if (client_socket == -1) {
    [self showLogsWithString:@"接受客戶端鏈接失敗"];
    NSLog(@"接受客戶端鏈接失敗");
   }else{
    NSString *acceptInfo = [NSString stringWithFormat:@"客戶端 in,socket:%d",client_socket];
    [self showLogsWithString:acceptInfo];

    //接受客戶端數(shù)據(jù)
    [self recvFromClinetWithSocket:client_socket];
   }
  }
 });
}

//接受客戶端數(shù)據(jù)
- (void)recvFromClinetWithSocket:(int)client_socket{
 while (1) {
  //接受客戶端傳來(lái)的數(shù)據(jù)
  char buf[1024] = {0};
  long iReturn = recv(client_socket, buf, 1024, 0);
  if (iReturn>0) {
   NSLog(@"客戶端來(lái)消息了");
   NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
   [self showLogsWithString:[NSString stringWithFormat:@"客戶端來(lái)消息了:%@",str]];
   [self checkRecvStr:str andClientSocket:client_socket];
  }else if (iReturn == -1){
   NSLog(@"讀取消息失敗");
   [self showLogsWithString:@"讀取消息失敗"];
   break;
  }else if (iReturn == 0){
   NSLog(@"客戶端走了");
   [self showLogsWithString:[NSString stringWithFormat:@"客戶端 out socket:%d",client_socket]];
   NSMutableArray *array = [NSMutableArray arrayWithArray:self.clientArray];
   for (ClientModel *model in array) {
    if (model.clientSocket == client_socket) {
     [self.clientNameArray removeObject:model.clientName];
     [self.clientArray removeObject:model];
    }
   }

   close(client_socket);

   break;
  }
 }
}

 //檢查接受到的字符串
- (void)checkRecvStr:(NSString*)str andClientSocket:(int)socket{
 if ([str hasPrefix:@"name:"]) {
  NSString *name = [str substringFromIndex:5];

  ClientModel *model = [[ClientModel alloc] init];
  model.clientSocket = socket;
  model.clientName = name;


  if (self.clientArray.count > 0) {
   int flag = 999;
   //用戶名不能相同
   int i = 0;

   for (ClientModel *client in self.clientArray) {

    //改名
    if (client.clientSocket == socket) {
     NSString *oldName = self.clientNameArray[i];
     self.clientNameArray[i] = name;
     self.clientArray[i] = model;

     for (ClientModel *oldclient in self.clientArray) {
      [self sendMsg:[NSString stringWithFormat:@"%@ 改名 %@",oldName,name] toClient:oldclient.clientSocket];
      [self showLogsWithString:[NSString stringWithFormat:@"%@ 改名 %@",oldName,name]];
      NSString *list = [self.clientNameArray componentsJoinedByString:@","];
      //向客戶端推送當(dāng)前在線列表
      [self sendMsg:[NSString stringWithFormat:@"list:%@",list] toClient:oldclient.clientSocket];
     }

     flag = 2;

    }else{
     if ([client.clientName isEqualToString:model.clientName]) {
      //用戶名已存在
      flag = 1;
      break;
     }
    }
    i++;

   }
   if (flag != 1 & flag != 2) {
    [self.clientArray addObject:model];
    [self.clientNameArray addObject:model.clientName];
    //向客戶端推送當(dāng)前在線列表
    for (ClientModel *client in self.clientArray) {
     [self sendMsg:[NSString stringWithFormat:@"%@,上線了",name] toClient:client.clientSocket];
     NSString *list = [self.clientNameArray componentsJoinedByString:@","];
     //向客戶端推送當(dāng)前在線列表
     [self sendMsg:[NSString stringWithFormat:@"list:%@",list] toClient:client.clientSocket];
    }

    //給當(dāng)前客戶端發(fā)送一條歡迎信息
    NSString *msg = [NSString stringWithFormat:@"Welcome %@ !",name];
    [self sendMsg:msg toClient:socket];
    [self showLogsWithString:msg];

   }else if (flag == 1){
    [self sendMsg:@"注冊(cè)用戶名失敗,用戶名已經(jīng)存在,請(qǐng)重新設(shè)置用戶名" toClient:socket];
    [self showLogsWithString:[NSString stringWithFormat:@"socket %d 注冊(cè)用戶名失敗,設(shè)置的用戶名已經(jīng)存在",socket]];

    for (ClientModel *model in self.clientArray) {

     [name isEqualToString:model.clientName];
    }



   }
  }else{
   [self.clientArray addObject:model];
   [self.clientNameArray addObject:model.clientName];
   //向客戶端推送當(dāng)前在線列表
   //給當(dāng)前客戶端發(fā)送一條歡迎信息
   NSString *msg = [NSString stringWithFormat:@"Welcome %@ !",name];
   [self sendMsg:msg toClient:socket];
   [self showLogsWithString:msg];

   NSString *list = [self.clientNameArray componentsJoinedByString:@","];
   //向客戶端推送當(dāng)前在線列表
   [self sendMsg:[NSString stringWithFormat:@"list:%@",list] toClient:socket];

  }

 }
 //給某人發(fā)消息
 else if ([str hasPrefix:@"to:"]){
  NSRange nameRange = [str rangeOfString:@"*"];
  NSString *name = [str substringWithRange:NSMakeRange(3, nameRange.location-3)];
  NSString *content = [str substringFromIndex:nameRange.location+1];
  NSString *fromClientName;
  //找出發(fā)送者
  for (ClientModel *model in self.clientArray) {
   if (socket == model.clientSocket) {
    fromClientName = model.clientName;
    break;
   }
  }

  //給目標(biāo)發(fā)送信息
  for (ClientModel *model in self.clientArray) {
   if ([name isEqualToString:model.clientName]) {
    NSString *msg = [NSString stringWithFormat:@"%@ to you\n%@",fromClientName,content];
    [self sendMsg:msg toClient:model.clientSocket];

    [self showLogsWithString:[NSString stringWithFormat:@"%@ 發(fā)送給 %@ 內(nèi)容是:%@",fromClientName,name,content]];
    break;

   }
  }

 }
}

//給客戶端發(fā)送信息
- (void)sendMsg:(NSString*)msg toClient:(int)socket{
 char *buf[1024] = {0};
 const char *p1 = (char*)buf;
 p1 = [msg cStringUsingEncoding:NSUTF8StringEncoding];
 send(socket, p1, 1024, 0);
}

 //在界面上顯示日志
- (void)showLogsWithString:(NSString*)str {
 dispatch_async(dispatch_get_main_queue(), ^{
  NSString *newStr = [NSString stringWithFormat:@"\n%@",str];
  self.textView.string = [self.textView.string stringByAppendingString:newStr];
 });
}

@end

客戶端

由于客戶端設(shè)計(jì)的就比較簡(jiǎn)單,所以代碼量也很少,全給你.

#import "ViewController.h"
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
//服務(wù)器socket
@property (nonatomic,assign)int server_socket;

//UI
@property (weak, nonatomic) IBOutlet UITextField *userNameField;
@property (weak, nonatomic) IBOutlet UITextView *chatView;
@property (weak, nonatomic) IBOutlet UITextField *msgField;
@property (weak, nonatomic) IBOutlet UILabel *toName;
@property (weak, nonatomic) IBOutlet UIView *onlineUserView;
@property (nonatomic,strong)UITableView *onlineTable;

//user列表
@property (nonatomic,strong)NSMutableArray *userArray;

@end

@implementation ViewController
- (NSMutableArray *)userArray {
 if (!_userArray) {
  _userArray = [NSMutableArray array];
 }
 return _userArray;
}
- (void)viewDidLoad {
 [super viewDidLoad];
 [self.userNameField becomeFirstResponder];
 self.userNameField.text = @"";
 self.msgField.text = @"";
 //添加table用戶列表
 self.onlineTable = [[UITableView alloc] initWithFrame:self.onlineUserView.frame style:UITableViewStylePlain];
 self.onlineTable.delegate = self;
 self.onlineTable.dataSource = self;
 [self.view addSubview:self.onlineTable];

 int server_socket = socket(AF_INET, SOCK_STREAM, 0);
 if (server_socket == -1) {
  NSLog(@"創(chuàng)建失敗");
 }else{
  //綁定地址和端口
  struct sockaddr_in server_addr;
  server_addr.sin_len = sizeof(struct sockaddr_in);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(1234);
  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  bzero(&(server_addr.sin_zero), 8);

  //接受客戶端的鏈接
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  dispatch_async(queue, ^{
   //創(chuàng)建新的socket
   int aResult = connect(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in));
   if (aResult == -1) {
    NSLog(@"鏈接失敗");
   }else{
    self.server_socket = server_socket;
    [self acceptFromServer];
   }
  });
 }
}

//從服務(wù)端接受消息
- (void)acceptFromServer{
 while (1) {
  //接受服務(wù)器傳來(lái)的數(shù)據(jù)
  char buf[1024];
  long iReturn = recv(self.server_socket, buf, 1024, 0);
  if (iReturn>0) {
   NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];

   //篩選前綴
   if ([str hasPrefix:@"list:"]) {
    NSString *arrayStr = [str substringFromIndex:5];
    NSArray *list = [arrayStr componentsSeparatedByString:@","];
    self.userArray = [NSMutableArray arrayWithArray:list];
    dispatch_async(dispatch_get_main_queue(), ^{
     [self.onlineTable reloadData];
    });
    NSLog(@"當(dāng)前在線用戶列表:%@",arrayStr);
   }else{
    //回到主線程 界面上顯示內(nèi)容
    [self showLogsWithString:str];
   }

  }else if (iReturn == -1){
   NSLog(@"接受失敗-1");
   break;
  }
 }
}

//在界面上顯示日志
- (void)showLogsWithString:(NSString*)str {
 dispatch_async(dispatch_get_main_queue(), ^{
  NSString *newStr = [NSString stringWithFormat:@"\n%@",str];
  self.chatView.text = [self.chatView.text stringByAppendingString:newStr];
 });
}

- (void)didReceiveMemoryWarning {
 [super didReceiveMemoryWarning];
 // Dispose of any resources that can be recreated.
}

//設(shè)置用戶名
- (IBAction)clickSetUserName:(id)sender {
 NSString *msg = [NSString stringWithFormat:@"name:%@",self.userNameField.text] ;
 [self sendMsg:msg];
// [self showLogsWithString:msg];
 [self.msgField becomeFirstResponder];
}

//發(fā)送信息
- (IBAction)clickSendMsg:(id)sender {
 if ([self.msgField.text isEqualToString:@""] || ![self.userArray containsObject:self.userNameField.text] || [self.toName.text isEqualToString:self.userNameField.text]) {
  [self showLogsWithString:@"請(qǐng)?jiān)O(shè)置用戶名、檢查發(fā)送對(duì)象、消息不能為空"];
  return;
 }
 NSString *msg = [NSString stringWithFormat:@"to:%@*%@",self.toName.text,self.msgField.text];
 [self sendMsg:msg];
 NSString *displayMsg = [NSString stringWithFormat:@"to:%@\n%@",self.toName.text,self.msgField.text];
 [self showLogsWithString:displayMsg];
 self.msgField.text = @"";

}

//給客戶端發(fā)送信息
- (void)sendMsg:(NSString*)msg {
 char *buf[1024] = {0};
 const char *p1 = (char*)buf;
 p1 = [msg cStringUsingEncoding:NSUTF8StringEncoding];
 send(self.server_socket, p1, 1024, 0);
}

#pragma mark - TableViewDelegate & dataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
 return self.userArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
 static NSString *cellId = @"onlinetableviewcellid";
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
 if (cell == nil) {
  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
 }else{
  NSLog(@"cell重用了");
 }
 cell.textLabel.text = self.userArray[indexPath.row];
 return cell;
}

//點(diǎn)擊cell
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
 self.toName.text = self.userArray[indexPath.row];
 [self.msgField becomeFirstResponder];
}
@end

Demo地址:IMsocketDemo_jb51.rar

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Flutter之可滾動(dòng)組件實(shí)例詳解

    Flutter之可滾動(dòng)組件實(shí)例詳解

    這篇文章主要為大家介紹了Flutter之可滾動(dòng)組件實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • iOS實(shí)現(xiàn)自定義表單實(shí)例代碼

    iOS實(shí)現(xiàn)自定義表單實(shí)例代碼

    表單對(duì)大家來(lái)說(shuō)應(yīng)該都不陌生,下面這篇文章主要給大家介紹了關(guān)于iOS如何實(shí)現(xiàn)自定義表單的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • ios中g(shù)etTime()的兼容性實(shí)例代碼

    ios中g(shù)etTime()的兼容性實(shí)例代碼

    在本篇文章里小編給大家整理的是關(guān)于ios中g(shù)etTime()的兼容性實(shí)例代碼,需要的朋友們可以學(xué)習(xí)下。
    2020-03-03
  • iOS之?dāng)?shù)據(jù)解析之XML解析詳解

    iOS之?dāng)?shù)據(jù)解析之XML解析詳解

    本篇文章主要介紹了iOS之?dāng)?shù)據(jù)解析之XML解析詳解,XML解析常見的兩種方式:DOM解析和SAX解析,有興趣的可以了解一下。
    2016-12-12
  • iOS逆向教程之動(dòng)態(tài)調(diào)試詳解

    iOS逆向教程之動(dòng)態(tài)調(diào)試詳解

    這篇文章主要給大家介紹了關(guān)于iOS逆向教程之動(dòng)態(tài)調(diào)試的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • iOS 截取字符串中兩個(gè)指定字符串中間的字符串方法

    iOS 截取字符串中兩個(gè)指定字符串中間的字符串方法

    下面小編就為大家分享一篇iOS 截取字符串中兩個(gè)指定字符串中間的字符串方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • iOS開發(fā)教程之UIRefreshControl使用的踩坑指南

    iOS開發(fā)教程之UIRefreshControl使用的踩坑指南

    UIRefreshControl是iOS6自帶的UITableView下拉刷新控件。下面這篇文章主要給大家介紹了關(guān)于iOS開發(fā)教程之UIRefreshControl使用的踩坑指南,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-04-04
  • iOS開發(fā)驗(yàn)證判斷語(yǔ)句之正則表達(dá)式小結(jié)

    iOS開發(fā)驗(yàn)證判斷語(yǔ)句之正則表達(dá)式小結(jié)

    最近在公司接手重構(gòu)一個(gè)項(xiàng)目,發(fā)現(xiàn)之前的開發(fā)在驗(yàn)證格式這塊寫的太亂了,到處都有相關(guān)的驗(yàn)證代碼,所以就有了這篇文章,供自己收藏也分享給有需要的朋友們參考借鑒,下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2016-12-12
  • iOS畢業(yè)設(shè)計(jì)之天氣預(yù)報(bào)App

    iOS畢業(yè)設(shè)計(jì)之天氣預(yù)報(bào)App

    這篇文章主要為大家詳細(xì)介紹了iOS畢業(yè)設(shè)計(jì)之天氣預(yù)報(bào)App,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • iOS利用AVPlayer播放網(wǎng)絡(luò)音樂(lè)的方法教程

    iOS利用AVPlayer播放網(wǎng)絡(luò)音樂(lè)的方法教程

    最近工作中遇到了一個(gè)需求,需要做一個(gè)在線音樂(lè)類的APP,通過(guò)一段時(shí)間的努力實(shí)現(xiàn)了,所以這篇文章主要給大家介紹了關(guān)于iOS利用AVPlayer播放網(wǎng)絡(luò)音樂(lè)的方法教程,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-05-05

最新評(píng)論