1. 程式人生 > >計算機網路_驗證UDP特性(一次未將報文資料讀完,剩餘部分將被丟棄)

計算機網路_驗證UDP特性(一次未將報文資料讀完,剩餘部分將被丟棄)

一、 思路

伺服器端和客戶端進行報文互動,客戶端每次向伺服器端傳送訊息,伺服器端只讀取5個有效字元,觀察情況:

二、 程式碼實現

#include<netinet/in.h> //struct sockaddr; struct sockaddr_in;
#include<sys/socket.h> //socket() bind() recvfrom() sendto()
#include<arpa/inet.h> //位元組序 htons() 返回以網路位元組序表示的16位無符號
#include<string.h> //memset()
#include<assert.h> //assert()
#include<stdio.h> //printf()

2.1 伺服器端

#include<netinet/in.h> //struct sockaddr; struct sockaddr_in;
#include<sys/socket.h> //socket() bind() recvfrom() sendto()
#include<arpa/inet.h> //位元組序 htons() 返回以網路位元組序表示的16位無符號
#include<string.h> //memset()
#include<assert.h> //assert()
#include<stdio.h> //printf()

int main()
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//地址族 套接字型別 協議
    assert(-1 != sockfd);

    struct sockaddr_in ser, cli;
    memset(&ser, 0, sizeof(ser)); //格式化伺服器端
  
    //設定伺服器端套接字
    ser.sin_family = AF_INET; //ipV4
    ser.sin_port = htons(6500);	//埠號為6000 主機序-> 網路序 
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");//ip地址

    //將套接字和地址結構進行繫結
    int res = bind(sockfd, (struct sockaddr*)&ser, sizeof(ser));
    assert(-1 != res);

    while(1)
    {
	    char recvbuf[6] = {'\0'}; //接受5個有效字元 保留一個結束符
	    int len = sizeof(cli); 
	
	    //套接字緩衝區的大小可能會改變
	    int n = recvfrom(sockfd, recvbuf, 5, 0, (struct sockaddr*)&cli, &len);
	
	    if(n <= 0) //本次失敗繼續進行下一次客戶機和伺服器端通訊
	    {
	        printf("recvfrom error!\n");
	        continue;
	    }

	    printf("%s\n", recvbuf); //列印輸出從客戶端接收的資料
    }
    close(sockfd); //關閉伺服器端套接字
}

2.2 客戶端

#include<string.h>  //memset()
#include<arpa/inet.h>	//位元組序處理 htons()
#include<sys/socket.h>	//sendto() recvfrom() socket()
#include<netinet/in.h>	//struct sockaddr; struct sockaddr_in;
#include<assert.h>  //assert()
#include<stdio.h>   //printf()
#include<stdlib.h>  //exit()

//main主函式傳參 argc反映陣列argv元素的個數
int main(int argc, char* argv[])
{
    if(argc < 3)
    {
	    printf("please choose server's IP && port\n");
	    exit(0);
    }
    
    //從命令列讀入埠號
    int port;
    sscanf(argv[2], "%d", &port);
    
    //地址族 套機字型別 所使用的協議 值位0表明和套接字型別自動匹配的協議
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
    assert(-1 != sockfd);

    struct sockaddr_in ser, cli;
    memset(&ser, 0, sizeof(ser));
    
    //配置伺服器端地址
    ser.sin_family = AF_INET;
    ser.sin_addr.s_addr = inet_addr(argv[1]);
    ser.sin_port = htons(port);

    while(1)
    {
	    //列印輸出提示語句
	    printf("please input:");
	    fflush(stdout);

	    char buf[128] = {'\0'}; 
	    fgets(buf, 127, stdin); //留下1位用作結束符
	    buf[strlen(buf) - 1] = '\0';

	    if(0 == strncmp(buf, "end", 3)) //客戶端命令列輸入end
	    {
	        close(sockfd);
	        break;
	    }

	    sendto(sockfd, buf, strlen(buf), 0,(struct sockaddr*)&ser, sizeof(ser));
    }
    close(sockfd); //關閉檔案描述符
}

2.3 執行結果

圖1 驗證結果

如圖 1所示,不管客戶機輸入的報文是長或段,因為在伺服器端的程式碼實現中,一次只會讀取5個有效字元。那如果伺服器端收到的字元多於5個怎麼辦?UDP是這樣處理的:你可以沒有時間處理,核心會為你保留;但是一旦進行讀取,必須一次性將報文全部讀取完,剩下的直接丟棄。