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

iOS socket網(wǎng)絡(luò)編程實(shí)例詳解

 更新時(shí)間:2017年03月19日 13:51:59   作者:jiuchabaikaishui  
socket是一個(gè)針對(duì)TCP和UDP編程的接口,你可以借助它建立TCP連接等。這篇文章主要介紹了iOS socket網(wǎng)絡(luò)編程 ,需要的朋友可以參考下

代碼下載

服務(wù)端代碼下載地址

客戶端代碼下載地址

相關(guān)概念

socket是一個(gè)針對(duì)TCP和UDP編程的接口,你可以借助它建立TCP連接等。socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過Socket,我們才能使用TCP/IP協(xié)議。Socket的出現(xiàn)只是使得程序員更方便地使用TCP/IP協(xié)議棧而已,是對(duì)TCP/IP協(xié)議的抽象,從而形成了我們知道的一些最基本的函數(shù)接口。

socket連接:socket連接就是所謂的長(zhǎng)連接,理論上客戶端和服務(wù)器端一旦建立起連接將不會(huì)主動(dòng)斷掉;但是由于各種環(huán)境因素可能會(huì)是連接斷開,比如說(shuō):服務(wù)器端或客戶端主機(jī)down了,網(wǎng)絡(luò)故障,或者兩者之間長(zhǎng)時(shí)間沒有數(shù)據(jù)傳輸,網(wǎng)絡(luò)防火墻可能會(huì)斷開該連接以釋放網(wǎng)絡(luò)資源。所以當(dāng)一個(gè)socket連接中沒有數(shù)據(jù)的傳輸,那么為了維持連接需要發(fā)送心跳消息~~具體心跳消息格式是開發(fā)者自己定義的。

TCP連接的三次握手:

第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);

第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);

第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。

握手過程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前,TCP 連接都將被一直保持下去。斷開連接時(shí)服務(wù)器和客戶端均可以主動(dòng)發(fā)起斷開TCP連接的請(qǐng)求,斷開過程需要經(jīng)過“四次握手”。

socket建立網(wǎng)絡(luò)連接的步驟

建立Socket連接至少需要一對(duì)套接字,其中一個(gè)運(yùn)行于客戶端,稱為ClientSocket ,另一個(gè)運(yùn)行于服務(wù)器端,稱為ServerSocket 。

套接字之間的連接過程分為三個(gè)步驟:服務(wù)器監(jiān)聽,客戶端請(qǐng)求,連接確認(rèn)。

1。服務(wù)器監(jiān)聽:服務(wù)器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態(tài),實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài),等待客戶端的連接請(qǐng)求。

2??蛻舳苏?qǐng)求:指客戶端的套接字提出連接請(qǐng)求,要連接的目標(biāo)是服務(wù)器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號(hào),然后就向服務(wù)器端套接字提出連接請(qǐng)求。

3。連接確認(rèn):當(dāng)服務(wù)器端套接字監(jiān)聽到或者說(shuō)接收到客戶端套接字的連接請(qǐng)求時(shí),就響應(yīng)客戶端套接字的請(qǐng)求,建立一個(gè)新的線程,把服務(wù)器端套接字的描述發(fā)給客戶端,一旦客戶端確認(rèn)了此描述,雙方就正式建立連接。而服務(wù)器端套接字繼續(xù)處于監(jiān)聽狀態(tài),繼續(xù)接收其他客戶端套接字的連接請(qǐng)求。

BSD socket

BSD socket:完全由c語(yǔ)言實(shí)現(xiàn),并且可以在Objective-C代碼中使用。

優(yōu)點(diǎn):不同平臺(tái)中易于移植

缺點(diǎn):

無(wú)法訪問操作系統(tǒng)內(nèi)建的網(wǎng)絡(luò)特性(比如系統(tǒng)范圍的VPN)。
更糟糕的是初始化socket連接并不會(huì)自動(dòng)打開設(shè)備的Wi-Fi或是蜂窩網(wǎng)絡(luò),無(wú)線網(wǎng)絡(luò)會(huì)智能的關(guān)閉以節(jié)省電池電量,任何通信連接都會(huì)失敗,除非其他網(wǎng)絡(luò)進(jìn)程激活了無(wú)線網(wǎng)。

CFNetwork對(duì)BSD Socket的分裝可以激活設(shè)備的無(wú)線網(wǎng),所以幾乎所有場(chǎng)景都建議使用CFNetwork而不是BSD Socket.

最常用的API:

1.int socket(int, int, int):創(chuàng)建并初始化新的socket,如果成功放回一個(gè)文件描述符,如果失敗返回0。

2.int bind(int, const struct sockaddr *, socklen_t):為指定的地址與端口號(hào)分配socket。

3.int listen(int, int) __DARWIN_ALIAS(listen):用于服務(wù)端監(jiān)聽客戶端

4.int accept(int, struct sockaddr * __restrict, socklen_t * __restrict):接受連接請(qǐng)求,將客戶端地址存儲(chǔ)到clientAddress中。

5.int connect(int, const struct sockaddr *, socklen_t):連接到指定的服務(wù)器。

6.ssize_t send(int, const void *, size_t, int):在socket上最多發(fā)送XX數(shù)據(jù)。

7.ssize_t recv(int, void *, size_t, int):在socket上最多讀取XX數(shù)據(jù)。

……

服務(wù)端邏輯:如果接收到客戶端發(fā)送過來(lái)”1”,那么回復(fù)”你猜!”;客戶端發(fā)送過來(lái)”2”,那么回復(fù)”謝謝!”;客戶端發(fā)送過來(lái)”3”,那么回復(fù)”對(duì)不起!”;客戶端發(fā)送過來(lái)”4”,那么回復(fù)”好的!”;客戶端發(fā)送過來(lái)其他的內(nèi)容,那么一半概率原樣回復(fù),一半概率回復(fù)”不知道你在說(shuō)什么!”。

屏幕快照 2017-03-16 下午2.16.02.png

創(chuàng)建服務(wù)端:

1.創(chuàng)建socket

struct sockaddr_in server_addr;
 server_addr.sin_len = sizeof(struct sockaddr_in);
 server_addr.sin_family = AF_INET;//AF_INET互聯(lián)網(wǎng)地址簇
 server_addr.sin_port = htons(port);
 server_addr.sin_addr.s_addr = inet_addr(address);
 bzero(&server_addr.sin_zero, 8);
 //創(chuàng)建socket
 int server_socket = socket(AF_INET, SOCK_STREAM, 0);//SOCK_STREAM 有鏈接
 if (server_socket == -1) {
  perror("socket error!");
  return 1;
 }

2.綁定socket:將創(chuàng)建的socket綁定到本地的IP地址和端口,此socket是半相關(guān)的,只是負(fù)責(zé)偵聽客戶端的連接請(qǐng)求,并不能用于和客戶端通信

 int bind_result = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
 if (bind_result == -1) {
  perror("bind error!");

  return 1;
 }

3.listen偵聽

 if (listen(server_socket, 5)) {
  perror("listen error!");
  return 1;
 }

4.接受客戶端連接

int client_socket;
 socklen_t address_len;
 struct sockaddr_in client_address;
 for (; ; ) {
  address_len = sizeof(client_address);
  client_socket = accept(server_socket, (struct sockaddr*)&client_address, &address_len);
  //1.使用多線程
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
   //這個(gè)函數(shù)進(jìn)行數(shù)據(jù)操作
   str_echo(client_socket);
  });
 }

5.接收和發(fā)送數(shù)據(jù)

 char buf[1024];
 while (1) {
  bzero(buf, 1024);
  long byte_num = recv(socket, buf, 1024, 0);
  if (byte_num < 0) {
   return;
  }
  buf[byte_num] = '\0';
  printf("client said:%s\n", buf);
  char *result;
  NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
  if ([str isEqualToString:@"1"]) {
   result = "你猜!";
  }
  else if ([str isEqualToString:@"2"])
  {
   result = "謝謝!";
  }
  else if ([str isEqualToString:@"3"])
  {
   result = "對(duì)不起!";
  }
  else if ([str isEqualToString:@"4"])
  {
   result = "好的!";
  }
  else
  {
   if (arc4random()%2 == 0) {
    result = "不知道你在說(shuō)什么!";
   }
   else
   {
    result = buf;
   }
  }
  send(socket, result, 1024, 0);
 }

創(chuàng)建客戶端:

struct sockaddr_in server_addr;
 server_addr.sin_len = sizeof(struct sockaddr_in);
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(11332);
 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 bzero(&(server_addr.sin_zero), 8);
 int server_socket = socket(AF_INET, SOCK_STREAM, 0);
 if (server_socket == -1) {
  perror("socket error");
  return 1;
 }
 char receive_msg[1024];
 char reply_msg[1024];
 if (connect(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in)) == 0) {
  //connect 成功之后,其實(shí)系統(tǒng)將你創(chuàng)建的socket綁定到一個(gè)系統(tǒng)分配的端口上,且其為全相關(guān),包含服務(wù)器端的信息,可以用來(lái)和服務(wù)器端進(jìn)行通信。
  while (1) {
   bzero(reply_msg, 1024);
   printf("replay:");
   scanf("%s", reply_msg);
   if (send(server_socket, reply_msg, 1024, 0) == -1) {
    perror("send error!");
    return 1;
   }
   bzero(receive_msg, 1024);
   long byte_num = recv(server_socket, receive_msg, 1024, 0);
   receive_msg[byte_num] = '\0';
   printf("server said:%s\n", receive_msg);
  }
 }
 return 0;

NSStream 讀寫文件

Cocoa Streams包含三個(gè)相關(guān)的類: NSStream、NSInputStream 和NSOutputStream。

NSStream:是個(gè)抽象類,定義了一些基本屬性和方法;

NSInputStream:是NSStream的子類,可通過它從NSData、File和socket中讀取數(shù)據(jù)流;

NSOutputStream:也是NSStream的子類,可通過它將數(shù)據(jù)流寫入NSData、File和socket。

還可以給stream對(duì)象設(shè)置Delegate(NSStreamDelegate),如果沒有精確了給stream指定Delegate,那么默認(rèn)將Delegate設(shè)置為其自己。

NSStreamDelegate只有一個(gè)方法
(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

NSStreamEventNone :改默認(rèn)值不代表任何事件

NSStreamEventOpenCompleted :socket被成功打開

NSStreamEventHasBytesAvailable :有可以讀取的字節(jié)

NSStreamEventHasSpaceAvailable :緩存中可以寫入字節(jié)

NSStreamEventErrorOccurred :操作出現(xiàn)錯(cuò)誤CFReadStreamCopyError()和CFWriteStreamCopyError()會(huì)提供更多錯(cuò)誤細(xì)節(jié)

NSStreamEventEndEncountered :socket達(dá)到字節(jié)流的末尾

通過NSStream對(duì)象讀數(shù)據(jù),可以分為如下步驟完成:

a) 從數(shù)據(jù)源創(chuàng)建和初始化一個(gè)NSStream對(duì)象;

b) 配置run loop,并打開stream對(duì)象;

c) 響應(yīng)NSInputStream事件(NSStreamDelegate);

d) 關(guān)閉NSInputStream對(duì)象。

- (void)viewDidLoad {
 [super viewDidLoad];
 NSString *documentStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
 NSString *dataPath = [documentStr stringByAppendingPathComponent:@"data.txt"];
 NSFileManager *manager = [NSFileManager defaultManager];
 if ([manager fileExistsAtPath:dataPath]) {
  self.read = YES;
  NSLog(@"string:%@", [NSString stringWithContentsOfFile:dataPath encoding:NSUTF8StringEncoding error:nil]);
  NSInputStream *inStream = [[NSInputStream alloc] initWithFileAtPath:dataPath];
  [inStream setDelegate:self];
  [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  [inStream open];
 }
 else
 {
  if ([manager createFileAtPath:dataPath contents:nil attributes:nil]) {
   self.read = NO;
   NSOutputStream *outStream = [[NSOutputStream alloc] initToFileAtPath:dataPath append:YES];
   [outStream setDelegate:self];
   [outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   [outStream open];
  }
  else
  {
   NSLog(@"文件創(chuàng)建失?。?);
  }
 }
}
#pragma mark - <NSStreamDelegate>代理方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
 if (self.read) {
  NSInputStream *inStream = (NSInputStream *)aStream;
  switch (eventCode) {
   case NSStreamEventHasBytesAvailable:
   {
    uint8_t data[1024];
    [inStream read:data maxLength:1024];
    printf("%s", data);
    [inStream close];
    [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    inStream = nil;
   }
    break;
   case NSStreamEventEndEncountered:
   {
    [inStream close];
    [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    inStream = nil;
   }
    break;
   default:
    break;
  }
 }
 else{
  NSOutputStream *outStream = (NSOutputStream *)aStream;
  switch (eventCode) {
   case NSStreamEventHasSpaceAvailable:
   {
    uint8_t data[] = "{name:'張三', age:10}";
    [outStream write:data maxLength:strlen((char *)data)];
    [outStream close];
    [outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    outStream = nil;
   }
    break;
   case NSStreamEventEndEncountered:
   {
    [outStream close];
    [outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    outStream = nil;
   }
    break;
   default:
    break;
  }
 }
}

NSStream Socket

NSStream類不支持在IOS平臺(tái)上創(chuàng)建socket連接,而CFStream支持在IOS平臺(tái)的socket行為。所以若知道遠(yuǎn)程主機(jī)的DNS或者是IP地址,可以使用CFStreamCreatePairWithSocketToHost函數(shù)來(lái)創(chuàng)建socket連接,通過該函數(shù)創(chuàng)建了CFStream類型為全雙工的socket連接,接著可以利用toll-free bridge,將CFStream對(duì)象轉(zhuǎn)換為NSStream對(duì)象。

通過NSStream對(duì)象進(jìn)行Socket通信,與通過NSStream進(jìn)行IO操作的步驟基本一樣:

a) 創(chuàng)建NSStream對(duì)象,通過CFStreamCreatePairWithSocketToHost函數(shù)創(chuàng)建CFReadStreamRef 和CFWriteStreamRef 對(duì)象;繼而將兩者轉(zhuǎn)換為NSInputStream 和NSOutputStream 對(duì)象;

b) 配置run loop,并打開NSInputStream 和NSOutputStream對(duì)象;

c) 響應(yīng)事件,在Delegate中響應(yīng)不同的信號(hào);

d) 關(guān)閉NSStream對(duì)象。

服務(wù)端:服務(wù)端依然使用上面例子的服務(wù)端

客戶端的實(shí)現(xiàn):點(diǎn)擊1~5這五個(gè)按鈕,分別從服務(wù)端返回不同的數(shù)據(jù),進(jìn)而展示出來(lái)。

屏幕快照 2017-03-16 下午3.55.49.png

由于實(shí)現(xiàn)相對(duì)簡(jiǎn)單,就不加闡述說(shuō)明了,實(shí)現(xiàn)代碼如下:

- (void)viewDidLoad {
 [super viewDidLoad];
 [self startSocket:@"127.0.0.1" andPort:11332];
}
- (void)startSocket:(NSString *)address andPort:(int)port
{
 CFReadStreamRef readRef;
 CFWriteStreamRef writeRef;
 CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)address, port, &readRef, &writeRef);
 NSInputStream *inputStream = (__bridge NSInputStream *)readRef;
 NSOutputStream *outputStream = (__bridge NSOutputStream *)writeRef;
 inputStream.delegate = self;
 outputStream.delegate = self;
 [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
 [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
 [inputStream open];
 [outputStream open];
 self.outputStream = outputStream;
}
- (IBAction)sendMsg:(UIButton *)sender {
 if (sender.currentTitle > 0) {
  const char *output = sender.currentTitle.UTF8String;
  [self.outputStream write:(const uint8_t *)output maxLength:strlen(output)];
 }
}
- (void)showMessage:(NSString *)msg
{
 if (!self.msgLabel) {
  UIFont *font = [UIFont systemFontOfSize:14];
  UIColor *color = [UIColor blackColor];
  UIColor *backColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2];
  UILabel *label = [[UILabel alloc] init];
  label.textColor = color;
  label.font = font;
  label.textAlignment = NSTextAlignmentCenter;
  label.backgroundColor = backColor;
  self.msgLabel = label;
 }
 CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
 CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
 CGFloat W = screenW - 16;
 CGSize size = [msg boundingRectWithSize:CGSizeMake(W, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.msgLabel.font} context:nil].size;
 W = size.width;
 CGFloat H = size.height;
 CGFloat X = (screenW - W)/2;
 CGFloat Y = (screenH - H)/2;
 self.msgLabel.frame = CGRectMake(X, Y, W, H);
 self.msgLabel.text = msg;
 [self.view addSubview:self.msgLabel];
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  [self.msgLabel removeFromSuperview];
 });
}
#pragma mark - <NSStreamDelegate>代理方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
 switch (eventCode) {
  case NSStreamEventNone:
   break;
  case NSStreamEventOpenCompleted:
   break;
  case NSStreamEventHasBytesAvailable:
  {
   uint8_t buf[1024];
   NSInteger len = 0;
   NSInputStream *inputStream = (NSInputStream *)aStream;
   len = [inputStream read:buf maxLength:1024];
   if (len) {
    [self showMessage:[NSString stringWithCString:(const char *)buf encoding:NSUTF8StringEncoding]];
   }
   break;
  }
  case NSStreamEventHasSpaceAvailable:
   break;
  case NSStreamEventErrorOccurred:
  {
   [aStream close];
   break;
  }
  case NSStreamEventEndEncountered:
  {
   [aStream close];
   [aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   aStream = nil;
   break;
  }
  default:
   break;
 }

以上所述是小編給大家介紹的iOS socket網(wǎng)絡(luò)編程,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大的!

相關(guān)文章

  • Kotlin中l(wèi)et、run、with、apply及also的用法和差別

    Kotlin中l(wèi)et、run、with、apply及also的用法和差別

    作用域函數(shù)是Kotlin比較重要的一個(gè)特性,分為5種let、run、with、apply及also,這五個(gè)函數(shù)的工作方式非常相似,但是我們需要了解這5種函數(shù)的差異,以便在不同的場(chǎng)景更好的利用它,這篇文章主要介紹了Kotlin中l(wèi)et、run、with、apply及also的差別,需要的朋友可以參考下
    2023-11-11
  • Java使用正則表達(dá)式驗(yàn)證用戶名和密碼的方法

    Java使用正則表達(dá)式驗(yàn)證用戶名和密碼的方法

    這篇文章主要介紹了Java使用正則表達(dá)式驗(yàn)證用戶名和密碼的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • java 學(xué)習(xí)筆記(入門篇)_java的安裝與配置

    java 學(xué)習(xí)筆記(入門篇)_java的安裝與配置

    學(xué)習(xí)Java已經(jīng)很長(zhǎng)時(shí)間了,由于基礎(chǔ)不好遇到問題就無(wú)從下手,所以,打算寫Java的隨手筆記來(lái)鞏固基礎(chǔ),加強(qiáng)學(xué)習(xí),接下來(lái)講解java的安裝,配置等,感興趣的朋友可以參考下
    2013-01-01
  • JDBC工具類實(shí)現(xiàn)登錄功能

    JDBC工具類實(shí)現(xiàn)登錄功能

    這篇文章主要為大家詳細(xì)介紹了JDBC工具類實(shí)現(xiàn)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java詳解entity轉(zhuǎn)換到vo過程

    Java詳解entity轉(zhuǎn)換到vo過程

    這篇文章將用實(shí)例來(lái)和大家介紹一下entity轉(zhuǎn)換到vo的方法過程。文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下
    2022-06-06
  • Java數(shù)組索引異常產(chǎn)生及解決方案

    Java數(shù)組索引異常產(chǎn)生及解決方案

    這篇文章主要介紹了Java數(shù)組索引異常產(chǎn)生及解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 淺談Spring自定義注解從入門到精通

    淺談Spring自定義注解從入門到精通

    這篇文章主要介紹了淺談Spring自定義注解從入門到精通,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java結(jié)構(gòu)型模式中的組合模式詳解

    Java結(jié)構(gòu)型模式中的組合模式詳解

    組合模式,又叫部分整體模式,它創(chuàng)建了對(duì)象組的數(shù)據(jù)結(jié)構(gòu)組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的訪問具有一致性。本文將通過示例為大家詳細(xì)介紹一下組合模式,需要的可以參考一下
    2023-02-02
  • J2ee 高并發(fā)情況下監(jiān)聽器實(shí)例詳解

    J2ee 高并發(fā)情況下監(jiān)聽器實(shí)例詳解

    這篇文章主要介紹了J2ee 高并發(fā)情況下監(jiān)聽器實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • SparkSQL使用快速入門

    SparkSQL使用快速入門

    spark SQL是spark的一個(gè)模塊,主要用于進(jìn)行結(jié)構(gòu)化數(shù)據(jù)的處理。它提供的最核心的編程抽象就是DataFrame。這篇文章主要介紹了SparkSQL使用快速入門,需要的朋友可以參考下
    2021-08-08

最新評(píng)論