亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS 使用 socket 實現即時通信示例(非第三方庫)

2020-07-26 02:56:07
字體:
來源:轉載
供稿:網友

其實寫這個socket一開始我是拒絕的。

因為大家學C 語言和linux基礎時肯定都有接觸,客戶端和服務端的通信也都了解過,加上現在很多開放的第三方庫都不需要我們來操作底層的通信。

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

效果

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

服務器

客戶端A

客戶端B

模型圖

分析

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

服務器

抽象一點分為:

1.創建線程等待接收客戶端的連接

2.接收并解析客戶端發來的消息

3.給客戶端發送消息

具體一點:

1.創建socket. 綁定端口.開始監聽.

2.創建線程.等待接收客戶端連接.

3.接收客戶端發來的消息

4.解析消息內容

a.設置用戶名

b.發送消息給指定客戶端

客戶端

抽象一點分為:

1.連接服務器

2.給服務器發送消息

3.接收服務器消息

4.解析消息內容

具體一點:

1.創建socket.綁定端口.連接服務器

2.發送消息

a.設置用戶名

b.給指定用戶發消息:按服務器格式拼接字符串

3.接收消息

a.普通消息

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

UI方面

服務器:其實不用什么UI放個控件展示下日志就是了

客戶端:比較簡單,一個俗套聊天室的界面,直接storyboard里拖拖控件設置約束了

DEMO而已別太當真

代碼部分

服務器

要使用scoket需要引用這三個頭文件

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

只有一個model,用來綁定用戶名和socket

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

只有一個文件全給你

#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. //創建socket int server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) {  NSLog(@"創建失敗");  [self showLogsWithString:@"socket創建失敗"]; }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(@"監聽失敗");    [self showLogsWithString:@"監聽失敗"];   }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.}//創建線程接受客戶端-(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, ^{  //創建新的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];    //接受客戶端數據    [self recvFromClinetWithSocket:client_socket];   }  } });}//接受客戶端數據- (void)recvFromClinetWithSocket:(int)client_socket{ while (1) {  //接受客戶端傳來的數據  char buf[1024] = {0};  long iReturn = recv(client_socket, buf, 1024, 0);  if (iReturn>0) {   NSLog(@"客戶端來消息了");   NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];   [self showLogsWithString:[NSString stringWithFormat:@"客戶端來消息了:%@",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:@","];      //向客戶端推送當前在線列表      [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];    //向客戶端推送當前在線列表    for (ClientModel *client in self.clientArray) {     [self sendMsg:[NSString stringWithFormat:@"%@,上線了",name] toClient:client.clientSocket];     NSString *list = [self.clientNameArray componentsJoinedByString:@","];     //向客戶端推送當前在線列表     [self sendMsg:[NSString stringWithFormat:@"list:%@",list] toClient:client.clientSocket];    }    //給當前客戶端發送一條歡迎信息    NSString *msg = [NSString stringWithFormat:@"Welcome %@ !",name];    [self sendMsg:msg toClient:socket];    [self showLogsWithString:msg];   }else if (flag == 1){    [self sendMsg:@"注冊用戶名失敗,用戶名已經存在,請重新設置用戶名" toClient:socket];    [self showLogsWithString:[NSString stringWithFormat:@"socket %d 注冊用戶名失敗,設置的用戶名已經存在",socket]];    for (ClientModel *model in self.clientArray) {     [name isEqualToString:model.clientName];    }   }  }else{   [self.clientArray addObject:model];   [self.clientNameArray addObject:model.clientName];   //向客戶端推送當前在線列表   //給當前客戶端發送一條歡迎信息   NSString *msg = [NSString stringWithFormat:@"Welcome %@ !",name];   [self sendMsg:msg toClient:socket];   [self showLogsWithString:msg];   NSString *list = [self.clientNameArray componentsJoinedByString:@","];   //向客戶端推送當前在線列表   [self sendMsg:[NSString stringWithFormat:@"list:%@",list] toClient:socket];  } } //給某人發消息 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;  //找出發送者  for (ClientModel *model in self.clientArray) {   if (socket == model.clientSocket) {    fromClientName = model.clientName;    break;   }  }  //給目標發送信息  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:@"%@ 發送給 %@ 內容是:%@",fromClientName,name,content]];    break;   }  } }}//給客戶端發送信息- (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

客戶端

由于客戶端設計的就比較簡單,所以代碼量也很少,全給你.

#import "ViewController.h"#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>//服務器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(@"創建失敗"); }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, ^{   //創建新的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];   }  }); }}//從服務端接受消息- (void)acceptFromServer{ while (1) {  //接受服務器傳來的數據  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(@"當前在線用戶列表:%@",arrayStr);   }else{    //回到主線程 界面上顯示內容    [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.}//設置用戶名- (IBAction)clickSetUserName:(id)sender { NSString *msg = [NSString stringWithFormat:@"name:%@",self.userNameField.text] ; [self sendMsg:msg];// [self showLogsWithString:msg]; [self.msgField becomeFirstResponder];}//發送信息- (IBAction)clickSendMsg:(id)sender { if ([self.msgField.text isEqualToString:@""] || ![self.userArray containsObject:self.userNameField.text] || [self.toName.text isEqualToString:self.userNameField.text]) {  [self showLogsWithString:@"請設置用戶名、檢查發送對象、消息不能為空"];  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 = @"";}//給客戶端發送信息- (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;}//點擊cell- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ self.toName.text = self.userArray[indexPath.row]; [self.msgField becomeFirstResponder];}@end

Demo地址:IMsocketDemo_jb51.rar

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美专区日韩视频| 久久99国产精品自在自在app| 久久久久久久国产| 2020国产精品视频| 欧美大学生性色视频| 日韩亚洲在线观看| 伊人伊人伊人久久| 日韩中文字幕视频在线| 国产精品一区二区久久久久| 精品视频—区二区三区免费| 国内精品久久影院| 97精品国产97久久久久久免费| 亚洲精品自产拍| 欧美在线观看www| 精品国产一区二区三区在线观看| 国产成人涩涩涩视频在线观看| 欧美大秀在线观看| 日韩中文字幕在线| 国产精品尤物福利片在线观看| 色中色综合影院手机版在线观看| 亚洲美女av电影| 国产精品大片wwwwww| 亚洲第一黄色网| 在线播放国产一区中文字幕剧情欧美| 亚洲欧美成人精品| 2019中文字幕在线| 国产精品美女无圣光视频| 欧美肥老妇视频| 亚洲人成网7777777国产| 日韩专区中文字幕| 亚洲成人教育av| 欧美www在线| 亚洲第一天堂无码专区| 久久久久久综合网天天| 国产91在线播放九色快色| 美女扒开尿口让男人操亚洲视频网站| 亚洲国产免费av| 高跟丝袜一区二区三区| 欧美激情区在线播放| 在线播放国产一区二区三区| 国产美女久久久| 国产精品福利片| 日韩av中文字幕在线| 国产精品91在线观看| 日韩小视频在线| 欧美激情一级精品国产| 欧美理论电影网| 国产精品久久久久久久久男| 亚洲欧美日韩中文在线| 久久成人av网站| 国产精品∨欧美精品v日韩精品| 亚洲精美色品网站| 日韩在线视频观看正片免费网站| 久久97精品久久久久久久不卡| 亚洲国产天堂网精品网站| 亚洲美女喷白浆| 国产精品久在线观看| 国产欧美日韩精品专区| 蜜月aⅴ免费一区二区三区| 96pao国产成视频永久免费| 国产精品96久久久久久又黄又硬| www.日韩av.com| 日韩欧美主播在线| 国产精品igao视频| 中文字幕欧美日韩精品| 国产综合香蕉五月婷在线| 色综合五月天导航| 26uuu日韩精品一区二区| 国产精品成人观看视频国产奇米| 午夜精品一区二区三区在线视频| 成人欧美一区二区三区黑人孕妇| 久久久亚洲精品视频| 国产专区欧美专区| 欧美激情第三页| 久久久国产成人精品| 日韩欧美在线视频| 91成人在线观看国产| 欧美精品videosex牲欧美| 国产亚洲成av人片在线观看桃| 国产精品久久久久久久久久久久久久| 狠狠操狠狠色综合网| 欧美性视频网站| 亚洲第一区第二区| 亚洲成人精品视频在线观看| 91在线网站视频| 亚洲自拍偷拍一区| 欧美性极品xxxx做受| 国产精品第2页| 欧美激情国内偷拍| 高清亚洲成在人网站天堂| 国产精品igao视频| 国产日韩中文字幕在线| 91精品国产91久久久久福利| 亚洲精品视频在线观看视频| 欧美猛交免费看| 国产精品一区二区3区| 国产精品久久久亚洲| 日韩专区在线观看| 欧美野外猛男的大粗鳮| 一本一本久久a久久精品综合小说| 国产精品老女人精品视频| 日韩av电影在线播放| 亚洲人成电影网站色| 丰满岳妇乱一区二区三区| 亚洲国产又黄又爽女人高潮的| 69视频在线免费观看| 91精品国产91久久久久久吃药| 国产在线日韩在线| 亚洲第一国产精品| 国产91久久婷婷一区二区| 成人欧美在线视频| 尤物tv国产一区| 久久亚洲综合国产精品99麻豆精品福利| 国产精品美女免费| 午夜精品一区二区三区在线| 日韩美女免费观看| 日韩美女毛茸茸| 国产精品成人免费电影| 欧美乱人伦中文字幕在线| 国语自产精品视频在线看抢先版图片| 亚洲精品理论电影| 欧美中文字幕视频在线观看| 亚洲欧洲一区二区三区在线观看| 欧美激情一区二区三级高清视频| 97视频在线观看成人| 中文字幕免费精品一区| 欧美午夜片在线免费观看| 色综合亚洲精品激情狠狠| 亚洲日韩欧美视频| 日本免费一区二区三区视频观看| 久久精品国产欧美激情| 欧洲成人在线观看| 色综合男人天堂| 中文字幕一区二区精品| 国产精品毛片a∨一区二区三区|国| 国产精品免费一区| 久久久精品国产一区二区| 日韩精品福利网站| 国产精品麻豆va在线播放| 中文精品99久久国产香蕉| 欧美日本精品在线| 欧美国产日韩一区| 中文字幕精品一区久久久久| 国产精品吴梦梦| 日韩男女性生活视频| 热99精品只有里视频精品| 在线电影av不卡网址| 91情侣偷在线精品国产| 亚洲午夜女主播在线直播| 欧美性xxxxx极品娇小| 91久久精品国产| 精品中文字幕视频| 上原亚衣av一区二区三区| 清纯唯美日韩制服另类| 亚洲国产精品热久久| 国产精品日日摸夜夜添夜夜av| 国产精品成av人在线视午夜片| 欧美成人精品不卡视频在线观看| 欧美性猛交xxxx黑人| 日本韩国在线不卡| 亚洲欧美在线一区| 欧美激情精品久久久| 亚洲大胆美女视频| 在线视频国产日韩|