国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Hello Network】網(wǎng)絡編程套接字(三)

這篇具有很好參考價值的文章主要介紹了【Hello Network】網(wǎng)絡編程套接字(三)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

作者:@小萌新
專欄:@網(wǎng)絡
作者簡介:大二學生 希望能和大家一起進步
本篇博客簡介:簡單介紹下各種類型的Tcp協(xié)議

我們在前面的網(wǎng)絡編程套接字(二)中寫出了一個單執(zhí)行流的服務器

我們再來回顧下它的運行

【Hello Network】網(wǎng)絡編程套接字(三)
我們首先啟動服務器 之后啟動客戶端1 最后啟動客戶端2

我們發(fā)現(xiàn)啟動客戶端1之后向服務器發(fā)送數(shù)據(jù)服務器很快的就回顯了一個數(shù)據(jù)并且打印了得到一個新連接

可是在客戶端2連接的時候卻沒有發(fā)生任何情況

【Hello Network】網(wǎng)絡編程套接字(三)

當我們的客戶端1退出的時候 服務器接受到了客戶端2的連接并且回顯了數(shù)據(jù)

單執(zhí)行流服務器

這是因為我們的服務器是單執(zhí)行流的 所以在同一時間只能有一個客戶端接受服務

當服務端調用accept函數(shù)獲取到連接后就給該客戶端提供服務 但在服務端提供服務期間可能會有其他客戶端發(fā)起連接請求 但由于當前服務器是單執(zhí)行流的 只能服務完當前客戶端后才能繼續(xù)服務下一個客戶端

客戶端為什么會顯示連接成功

服務器是處于監(jiān)聽狀態(tài)的 在我們的客戶端2發(fā)送連接請求的時候實際上已經被監(jiān)聽到了 只不過服務端沒有調用accept函數(shù)將該連接獲取上來

實際在底層會為我們維護一個連接隊列 服務端沒有accept的新連接就會放到這個連接隊列當中 而這個連接隊列的最大長度就是通過listen函數(shù)的第二個參數(shù)來指定的 因此服務端雖然沒有獲取第二個客戶端發(fā)來的連接請求 但是在第二個客戶端那里顯示是連接成功的

如何解決?

單執(zhí)行流的服務器一次只能給一個客戶端提供服務 此時服務器的資源并沒有得到充分利用 因此服務器一般是不會寫成單執(zhí)行流的 要解決這個問題就需要將服務器改為多執(zhí)行流的 此時就要引入多進程或多線程

多進程版的TCP網(wǎng)絡程序

我們將之前的單執(zhí)行流服務器改為多進程服務器

當服務端調用accept函數(shù)獲取到新連接后不是由當前執(zhí)行流為該連接提供服務 而是當前執(zhí)行流調用fork函數(shù)創(chuàng)建子進程 然后讓子進程為父進程獲取到的連接提供服務

由于父子進程是兩個不同的執(zhí)行流 當父進程調用fork創(chuàng)建出子進程后 父進程就可以繼續(xù)從監(jiān)聽套接字當中獲取新連接 而不用關心獲取上來的連接是否服務完畢

子進程繼承父進程的文件描述符表

需要注意的是 文件描述符表是隸屬于一個進程的 子進程創(chuàng)建后會繼承父進程的文件描述符表

比如父進程打開了一個文件 該文件對應的文件描述符是3 此時父進程創(chuàng)建的子進程的3號文件描述符也會指向這個打開的文件 而如果子進程再創(chuàng)建一個子進程 那么子進程創(chuàng)建的子進程的3號文件描述符也同樣會指向這個打開的文件

【Hello Network】網(wǎng)絡編程套接字(三)

但是當父進程創(chuàng)建出子進程之后 父子進程就會保持獨立性了 此時父進程文件描述符表的變化不會影響子進程的文件描述符表

在我們之前學習的匿名管道通信時 我們就是使用的這個原理

父進程首先使用pipe函數(shù)得到兩個文件描述符 一個是文件讀端一個是文件的寫端 此時父進程創(chuàng)建的子進程會繼承這兩個文件描述符

之后父子進程一個關閉管道的讀端 另一個關閉管道的寫端 這時父子進程文件描述符表的變化是不會相互影響的 此后父子進程就可以通過這個管道進行單向通信了

對于套接字文件也是一樣的 父進程創(chuàng)建的子進程也會繼承父進程的套接字文件 此時子進程就能夠對特定的套接字文件進行讀寫操作 進而完成對對應客戶端的服務

等待子進程問題

當父進程創(chuàng)建出子進程后 父進程是需要等待子進程退出的 否則子進程會變成僵尸進程 進而造成內存泄漏

因此服務端創(chuàng)建子進程后需要調用wait或waitpid函數(shù)對子進程進行等待

此時我們就有兩種等待方式 阻塞式等待和非阻塞式等待:

  • 如果服務端采用阻塞的方式等待子進程 那么服務端還是需要等待服務完當前客戶端 才能繼續(xù)獲取下一個連接請求此時服務端仍然是以一種串行的方式為客戶端提供服務
  • 如果服務端采用非阻塞的方式等待子進程 雖然在子進程為客戶端提供服務期間服務端可以繼續(xù)獲取新連接 但此時服務端就需要將所有子進程的PID保存下來 并且需要不斷花費時間檢測子進程是否退出

總之 服務端要等待子進程退出 無論采用阻塞式等待還是非阻塞式等待 都不盡人意 此時我們可以考慮讓服務端不等待子進程退出

不等待子進程退出的方式

讓父進程不等待子進程退出 常見的方式有兩種:

  • 捕捉SIGCHLD信號 將其處理動作設置為忽略
  • 讓父進程創(chuàng)建子進程 子進程再創(chuàng)建孫子進程 最后讓孫子進程為客戶端提供服務

捕捉SIGCHLD信號

實際當子進程退出時會給父進程發(fā)送SIGCHLD信號 如果父進程將SIGCHLD信號進行捕捉 并將該信號的處理動作設置為忽略 此時父進程就只需專心處理自己的工作 不必關心子進程了

下面是我們的處理代碼 其中比較核心的代碼是這一行

signal(SIGCHLD, SIG_IGN);
class TcpServer
{
public:
	void Start()
	{
		signal(SIGCHLD, SIG_IGN); //忽略SIGCHLD信號
		for (;;){
			//獲取連接
			struct sockaddr_in peer;
			memset(&peer, '\0', sizeof(peer));
			socklen_t len = sizeof(peer);
			int sock = accept(_listen_sock, (struct sockaddr*)&peer, &len);
			if (sock < 0){
				std::cerr << "accept error, continue next" << std::endl;
				continue;
			}
			std::string client_ip = inet_ntoa(peer.sin_addr);
			int client_port = ntohs(peer.sin_port);
			std::cout << "get a new link->" << sock << " [" << client_ip << "]:" << client_port << std::endl;
			
			pid_t id = fork();
			if (id == 0){ //child
				//處理請求
				Service(sock, client_ip, client_port);
				exit(0); //子進程提供完服務退出
			}
		}
	}
private:
	int _listen_sock; //監(jiān)聽套接字
	int _port; //端口號
};

下面是在此運行的結果

【Hello Network】網(wǎng)絡編程套接字(三)

我們可以發(fā)現(xiàn) 加上這幾行代碼之后我們就可以讓服務器服務多個客戶端了

讓孫子進程執(zhí)行任務

我們也可以讓服務端創(chuàng)建出來的子進程再次進行fork 讓孫子進程為客戶端提供服務 此時我們就不用等待孫子進程退出了

命名:

  • 爺爺進程:在服務端調用accept函數(shù)獲取客戶端連接請求的進程
  • 爸爸進程:由爺爺進程調用fork函數(shù)創(chuàng)建出來的進程
  • 孫子進程:由爸爸進程調用fork函數(shù)創(chuàng)建出來的進程 該進程調用Service函數(shù)為客戶端提供服務

我們讓爸爸進程創(chuàng)建完孫子進程后立刻退出 此時服務進程(爺爺進程)調用wait/waitpid函數(shù)等待爸爸進程就能立刻等待成功 此后服務進程就能繼續(xù)調用accept函數(shù)獲取其他客戶端的連接請求

不需要等待孫子進程退出

這里主要是利用了孤兒進程的原理 當孫子進程的父進程死亡后它就會被1號進程也就是init進程領養(yǎng) 當孫子進程運行完畢之后它的資源會由1號進程進行回收 我們也就不需要擔心僵尸進程的問題了

關閉對應的文件描述符

服務進程(爺爺進程)調用accept函數(shù)獲取到新連接后 會讓孫子進程為該連接提供服務,此時服務進程已經將文件描述符表繼承給了爸爸進程 而爸爸進程又會調用fork函數(shù)創(chuàng)建出孫子進程 然后再將文件描述符表繼承給孫子進程。

而父子進程創(chuàng)建后 它們各自的文件描述符表是獨立的 不會相互影響

因此服務進程在調用fork函數(shù)后 服務進程就不需要再關心剛才從accept函數(shù)獲取到的文件描述符了 此時服務進程就可以調用close函數(shù)將該文件描述符進行關閉

同樣的 對于爸爸進程和孫子進程來說 它們是不需要關心從服務進程(爺爺進程)繼承下來的監(jiān)聽套接字的 因此爸爸進程可以將監(jiān)聽套接字關掉

關閉文件描述符的必要性:

  • 對于服務進程來說 當它調用fork函數(shù)后就必須將從accept函數(shù)獲取的文件描述符關掉 因為服務進程會不斷調用accept函數(shù)獲取新的文件描述符(服務套接字) 如果服務進程不及時關掉不用的文件描述符 最終服務進程中可用的文件描述符就會越來越少
  • 而對于爸爸進程和孫子進程來說 還是建議關閉從服務進程繼承下來的監(jiān)聽套接字 實際就算它們不關閉監(jiān)聽套接字 最終也只會導致這一個文件描述符泄漏 但一般還是建議關上 因為孫子進程在提供服務時可能會對監(jiān)聽套接字進行某種誤操作 此時就會對監(jiān)聽套接字當中的數(shù)據(jù)造成影響
class TcpServer
{
public:
	void Start()
	{
		for (;;){
			//獲取連接
			struct sockaddr_in peer;
			memset(&peer, '\0', sizeof(peer));
			socklen_t len = sizeof(peer);
			int sock = accept(_listen_sock, (struct sockaddr*)&peer, &len);
			if (sock < 0){
				std::cerr << "accept error, continue next" << std::endl;
				continue;
			}
			std::string client_ip = inet_ntoa(peer.sin_addr);
			int client_port = ntohs(peer.sin_port);
			std::cout << "get a new link->" << sock << " [" << client_ip << "]:" << client_port << std::endl;
			
			pid_t id = fork();
			if (id == 0){ //child
				close(_listen_sock); //child關閉監(jiān)聽套接字
				if (fork() > 0){
					exit(0); //爸爸進程直接退出
				}
				//處理請求
				Service(sock, client_ip, client_port); //孫子進程提供服務
				exit(0); //孫子進程提供完服務退出
			}
			close(sock); //father關閉為連接提供服務的套接字
			waitpid(id, nullptr, 0); //等待爸爸進程(會立刻等待成功)
		}
	}
private:
	int _listen_sock; //監(jiān)聽套接字
	int _port; //端口號
};

運行結果如下

【Hello Network】網(wǎng)絡編程套接字(三)
我們可以發(fā)現(xiàn)當前服務器可以支持多個客戶端訪問并且得到的文件描述符都是4

多線程TCP網(wǎng)絡程序

創(chuàng)建進程的成本是很高的,創(chuàng)建進程時需要創(chuàng)建該進程對應的進程控制塊(task_struct)、進程地址空間(mm_struct)、頁表等數(shù)據(jù)結構。而創(chuàng)建線程的成本比創(chuàng)建進程的成本會小得多,因為線程本質是在進程地址空間內運行,創(chuàng)建出來的線程會共享該進程的大部分資源,因此在實現(xiàn)多執(zhí)行流的服務器時最好采用多線程進行實現(xiàn)

當服務進程調用accept函數(shù)獲取到一個新連接后 就可以直接創(chuàng)建一個線程 讓該線程為對應客戶端提供服務

當然 主線程(服務進程)創(chuàng)建出新線程后 也是需要等待新線程退出的 否則也會造成類似于僵尸進程這樣的問題 但對于線程來說 如果不想讓主線程等待新線程退出 可以讓創(chuàng)建出來的新線程調用pthread_detach函數(shù)進行線程分離 當這個線程退出時系統(tǒng)會自動回收該線程所對應的資源 此時主線程(服務進程)就可以繼續(xù)調用accept函數(shù)獲取新連接 而讓新線程去服務對應的客戶端

各個線程共享同一張文件描述符表

文件描述符表維護的是進程與文件之間的對應關系 因此一個進程對應一張文件描述符表

而主線程創(chuàng)建出來的新線程依舊屬于這個進程 因此創(chuàng)建線程時并不會為該線程創(chuàng)建獨立的文件描述符表 所有的線程看到的都是同一張文件描述符表

【Hello Network】網(wǎng)絡編程套接字(三)

因此當服務進程(主線程)調用accept函數(shù)獲取到一個文件描述符后 其他創(chuàng)建的新線程是能夠直接訪問這個文件描述符的

需要注意的是 雖然新線程能夠直接訪問主線程accept上來的文件描述符 但此時新線程并不知道它所服務的客戶端對應的是哪一個文件描述符

因此主線程創(chuàng)建新線程后需要告訴新線程對應應該訪問的文件描述符的值 也就是告訴每個新線程在服務客戶端時 應該對哪一個套接字進行操作

文件描述符關閉的問題

由于此時所有線程看到的都是同一張文件描述符表 因此當某個線程要對這張文件描述符表做某種操作時 不僅要考慮當前線程 還要考慮其他線程

  • 對于主線程accept上來的文件描述符 主線程不能對其進行關閉操作 該文件描述符的關閉操作應該由新線程來執(zhí)行 因為是新線程為客戶端提供服務的 只有當新線程為客戶端提供的服務結束后才能將該文件描述符關閉
  • 對于監(jiān)聽套接字 雖然創(chuàng)建出來的新線程不必關心監(jiān)聽套接字 但新線程不能將監(jiān)聽套接字對應的文件描述符關閉 否則主線程就無法從監(jiān)聽套接字當中獲取新連接了

Service函數(shù)定義為靜態(tài)成員函數(shù)

由于調用pthread_create函數(shù)創(chuàng)建線程時 新線程的執(zhí)行例程是一個參數(shù)為void* 返回值為void*的函數(shù) 如果我們要將這個執(zhí)行例程定義到類內 就需要將其定義為靜態(tài)成員函數(shù) 否則這個執(zhí)行例程的第一個參數(shù)是隱藏的this指針

在線程的執(zhí)行例程當中會調用Service函數(shù) 由于執(zhí)行例程是靜態(tài)成員函數(shù) 靜態(tài)成員函數(shù)無法調用非靜態(tài)成員函數(shù) 因此我們需要將Service函數(shù)定義為靜態(tài)成員函數(shù) 恰好Service函數(shù)內部進行的操作都是與類無關的 因此我們直接在Service函數(shù)前面加上一個static即可

Rontine函數(shù)

  static void* Rontine(void* arg)
  {
    pthread_detach(pthread_self());
    int* p = (int*)arg;

    int sock = *p;
    Service(sock);
    return nullptr;
  }

Start函數(shù)

  void Start()
  {
    while(true)
    {
      // accept 
      struct sockaddr_in peer; 
      memset(&peer , '\0' , sizeof(peer));
      socklen_t len = sizeof(peer);

      int sock = accept(_sockfd , (struct sockaddr*)&peer , &len);
      if (sock < 0)
      {
        cout << "accept error" << endl; 
        continue;
      }

      int* p = &sock; 
      pthread_t tid;
      pthread_create(&tid , nullptr , Rontine , (void*)p);
    }
  }

運行結果如下
【Hello Network】網(wǎng)絡編程套接字(三)

線程池版多線程TCP網(wǎng)絡程序

當前多線程版的服務器存在的問題:

  • 每當有新連接到來時 服務端的主線程都會重新為該客戶端創(chuàng)建為其提供服務的新線程 而當服務結束后又會將該新線程銷毀 這樣做不僅麻煩 而且效率低下 每當連接到來的時候服務端才創(chuàng)建對應提供服務的線程
  • 如果有大量的客戶端連接請求 此時服務端要為每一個客戶端創(chuàng)建對應的服務線程 計算機當中的線程越多 CPU的壓力就越大 因為CPU要不斷在這些線程之間來回切換 此時CPU在調度線程的時候 線程和線程之間切換的成本就會變得很高
  • 一旦線程太多 每一個線程再次被調度的周期就變長了 而線程是為客戶端提供服務的 線程被調度的周期變長 客戶端也遲遲得不到應答

解決思路

  • 可以在服務端預先創(chuàng)建一批線程,當有客戶端請求連接時就讓這些線程為客戶端提供服務,此時客戶端一來就有線程為其提供服務,而不是當客戶端來了才創(chuàng)建對應的服務線程。
  • 當某個線程為客戶端提供完服務后,不要讓該線程退出,而是讓該線程繼續(xù)為下一個客戶端提供服務,如果當前沒有客戶端連接請求,則可以讓該線程先進入休眠狀態(tài),當有客戶端連接到來時再將該線程喚醒。
  • 服務端創(chuàng)建的這一批線程的數(shù)量不能太多,此時CPU的壓力也就不會太大。此外,如果有客戶端連接到來,但此時這一批線程都在給其他客戶端提供服務,這時服務端不應該再創(chuàng)建線程,而應該讓這個新來的連接請求在全連接隊列進行排隊,等服務端這一批線程中有空閑線程后,再將該連接請求獲取上來并為其提供服務。

我們可以發(fā)現(xiàn) 我們前面做的線程池可以完美解決上面的問題

線程池

服務類新增線程池成員

服務類新增線程池成員

  • 當實例化服務器對象時,先將這個線程池指針先初始化為空。
  • 當服務器初始化完畢后,再實際構造這個線程池對象,在構造線程池對象時可以指定線程池當中線程的個數(shù),也可以不指定,此時默認線程的個數(shù)為5。
  • 在啟動服務器之前對線程池進行初始化,此時就會將線程池當中的若干線程創(chuàng)建出來,而這些線程創(chuàng)建出來后就會不斷檢測任務隊列,從任務隊列當中拿出任務進行處理。

現(xiàn)在當服務進程調用accept函數(shù)獲取到一個連接請求后,就會根據(jù)該客戶端的套接字、IP地址以及端口號構建出一個任務,然后調用線程池提供的Push接口將該任務塞入任務隊列

這實際也是一個生產者消費者模型,其中服務進程就作為了任務的生產者,而后端線程池當中的若干線程就不斷從任務隊列當中獲取任務進行處理,它們承擔的就是消費者的角色,其中生產者和消費者的交易場所就是線程池當中的任務隊列。

    void Start()                                                           
    {                                                                      
      _tp->ThreadPoolInit();                                               
      while(true)                                                          
      {                                                                    
        // accept                                                          
        struct sockaddr_in peer;                                           
        memset(&peer , '\0' , sizeof(peer));                               
        socklen_t len = sizeof(peer);                                      
                                                                           
        int sock = accept(_sockfd , (struct sockaddr*)&peer , &len);       
        if (sock < 0)                                                      
        {                                                                  
          cout << "accept error" << endl;                                  
          continue;                                                        
        }                                                                                                                                           
                                                                           
E>      Task task(port);                                                   
        _tp->Push(task);    
      }                                                                   
    }  

設計任務類

現(xiàn)在我們要做的就是設計一個任務類,該任務類當中需要包含客戶端對應的套接字、IP地址、端口號,表示該任務是為哪一個客戶端提供服務,對應操作的套接字是哪一個。

此外,任務類當中需要包含一個Run方法,當線程池中的線程拿到任務后就會直接調用這個Run方法對該任務進行處理,而實際處理這個任務的方法就是服務類當中的Service函數(shù),服務端就是通過調用Service函數(shù)為客戶端提供服務的。

我們可以直接拿出服務類當中的Service函數(shù),將其放到任務類當中作為任務類當中的Run方法,但這實際不利于軟件分層。我們可以給任務類新增一個仿函數(shù)成員,當執(zhí)行任務類當中的Run方法處理任務時就可以以回調的方式處理該任務。

Handler類

  class Handler
  {
    Handler() = default;
    void operator()(int sock)
    {
        cout << "get a new linl :  " << sock  << endl;
        char buff[1024];                                                                                                                                                   
        while(true)     
        {                          
          ssize_t size = read(sock , buff , sizeof(buff) - 1);
          if (size > 0)               
          {
            buff[size] = 0; // '\0'
            cout << buff << endl;
            write(sock , buff , size);   
          }
          else if (size == 0)
          {       
            cout << "read close" << endl;
            break;                                                                                                                                  
          }
          else
          {         
            cout << "unknown error" << endl;      
          }
       }
        close(sock);
        cout << "Service end sock closed" << endl;
    }
  };

Task類

#pragma once     
#include "sever.cc"    
#include <iostream>    
using namespace std;    
class Task    
{    
  private:    
    int _sock;    
    Handler _handler;    
  public:    
    Task(int sock)    
      :_sock(sock)                                                                                                                                  
    {}    
    Task() = default;   
    void run()    
    {    
      _handler(_sock);    
    }    
};  

這樣子我們線程池版本的TCP網(wǎng)絡程序就基本完成了

下面是運行結果

【Hello Network】網(wǎng)絡編程套接字(三)文章來源地址http://www.zghlxwxcb.cn/news/detail-421384.html

到了這里,關于【Hello Network】網(wǎng)絡編程套接字(三)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【網(wǎng)絡】網(wǎng)絡編程套接字

    【網(wǎng)絡】網(wǎng)絡編程套接字

    目錄 一、預備知識 1、網(wǎng)絡通信理解 2、源IP地址和目的IP地址 3、端口號 二、網(wǎng)絡字節(jié)序 三、socket編程接口 1、socket常見API 2、sockaddr結構 3、sockaddr結構體 3.1、sockaddr結構體 3.2、sockaddr_in結構體 四、簡單的UDP網(wǎng)絡程序 1、創(chuàng)建套接字接口 2、綁定端口號 3、服務器運行 4、創(chuàng)建

    2024年02月14日
    瀏覽(91)
  • 【網(wǎng)絡編程】網(wǎng)絡編程套接字(一)

    【網(wǎng)絡編程】網(wǎng)絡編程套接字(一)

    端口號(port)是傳輸層協(xié)議的內容. 端口號是一個2字節(jié)16位的整數(shù); 端口號用來標識一個進程, 告訴操作系統(tǒng), 當前的這個數(shù)據(jù)要交給哪一個進程來處理; IP地址 + 端口號能夠標識網(wǎng)絡上的某一臺主機的某一個進程; 一個端口號只能被一個進程占用. 既然端口號是用來標識一個進程,

    2024年02月12日
    瀏覽(646)
  • 網(wǎng)絡編程2(套接字編程)

    網(wǎng)絡編程2(套接字編程)

    套接字編程:如何編寫一個網(wǎng)絡通信程序 1.網(wǎng)絡通信的數(shù)據(jù)中都會包含一個完整的五元組: sip,sport,dip,dport,protocol(源IP,源端口,對端IP,對端端口,協(xié)議) 五元組完整的描述了數(shù)據(jù)從哪來,到哪去,用什么數(shù)據(jù)格式 2.網(wǎng)絡通信–兩個主機進程之間的通信:客戶端服務

    2023年04月09日
    瀏覽(116)
  • 【網(wǎng)絡】網(wǎng)絡編程套接字(一)

    【網(wǎng)絡】網(wǎng)絡編程套接字(一)

    在前面我們說過可以使用IP地址來標識一臺主機,但是我們光有IP地址就可以完成通信了嘛? 答案是:不可以,當我們的主機接收到了數(shù)據(jù)以后還要確定這個數(shù)據(jù)是發(fā)送給哪一個進程的,兩臺主機的兩個軟件進行網(wǎng)絡通信時,我們還需要有一個其他的標識來區(qū)分出這個數(shù)據(jù)要給

    2024年02月06日
    瀏覽(96)
  • 【JaveEE】網(wǎng)絡編程之TCP套接字、UDP套接字

    【JaveEE】網(wǎng)絡編程之TCP套接字、UDP套接字

    目錄 1.網(wǎng)絡編程的基本概念 1.1為什么需要網(wǎng)絡編程? 1.2服務端與用戶端 1.3網(wǎng)絡編程五元組? 1.4套接字的概念 2.UDP套接字編程 2.1UDP套接字的特點 ?2.2UDP套接字API 2.2.1DatagramSocket類 2.2.2DatagramPacket類? 2.2.3基于UDP的回顯程序 2.2.4基于UDP的單詞查詢? 3.TCP套接字編程 3.1TCP套接字的特

    2023年04月13日
    瀏覽(915)
  • 【JavaEE】網(wǎng)絡編程之TCP套接字、UDP套接字

    【JavaEE】網(wǎng)絡編程之TCP套接字、UDP套接字

    目錄 1.網(wǎng)絡編程的基本概念 1.1為什么需要網(wǎng)絡編程? 1.2服務端與用戶端 1.3網(wǎng)絡編程五元組? 1.4套接字的概念 2.UDP套接字編程 2.1UDP套接字的特點 ?2.2UDP套接字API 2.2.1DatagramSocket類 2.2.2DatagramPacket類? 2.2.3基于UDP的回顯程序 2.2.4基于UDP的單詞查詢? 3.TCP套接字編程 3.1TCP套接字的特

    2023年04月20日
    瀏覽(120)
  • 【Linux網(wǎng)絡編程】網(wǎng)絡編程套接字二

    【Linux網(wǎng)絡編程】網(wǎng)絡編程套接字二

    喜歡的點贊,收藏,關注一下把! TCP和UDP在編程接口上是非常像的,前面我們說過TCP是面向連接的,UDP我們上篇博客也寫過了,我們發(fā)現(xiàn)UDP服務端客戶端寫好啟動直接就發(fā)消息了沒有建立連接。TCP是建立連接的,注定在寫的時候肯定有寫不一樣的地方。具體怎么不一樣,我們

    2024年04月15日
    瀏覽(101)
  • 網(wǎng)絡編程套接字(3)——Java數(shù)據(jù)報套接字(UDP協(xié)議)

    網(wǎng)絡編程套接字(3)——Java數(shù)據(jù)報套接字(UDP協(xié)議)

    目錄 一、Java數(shù)據(jù)報套接字通信模型 二、UDP數(shù)據(jù)報套接字編程 1、DatagramSocket ????????(1)DatagramSocket構造方法 ????????(2)DatagramSocket方法 2、DatagramPacket ????????(1)DatagramPacket構造方法 ????????(2)DatagramPacket方法 3、InetSocketAddress 三、代碼示例:回顯服務

    2024年03月12日
    瀏覽(233)
  • 網(wǎng)絡編程【TCP流套接字編程】

    網(wǎng)絡編程【TCP流套接字編程】

    目錄 TCP流套接字編程 1.ServerSocket API 2.Socket API 3.TCP中的長短連接 4.回顯程序(短連接) 5.服務器和客戶端它們的交互過程 6.運行結果及修改代碼 ? ??兩個核心: ServerSocket? ? ?Socket 1.ServerSocket API ? ServerSocket 是創(chuàng)建?TCP服務端Socket的API ServerSocket 構造方法: ServerSocket 方法 :

    2023年04月12日
    瀏覽(573)
  • UDP網(wǎng)絡套接字編程

    UDP網(wǎng)絡套接字編程

    先來說說數(shù)據(jù)在網(wǎng)絡上的傳輸過程吧,我們知道系統(tǒng)其實終究是根據(jù)馮諾依曼來構成的,而網(wǎng)絡數(shù)據(jù)是怎么發(fā)的呢? 其實很簡單,網(wǎng)絡有五層。如下: 如上圖,我們知道的是,每層對應的操作系統(tǒng)中的那些地方,有些可能說是網(wǎng)絡有七層,其實和這個五層一樣的。下面我們

    2024年02月04日
    瀏覽(97)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包