Linux網路程式設計常見面試題

shuilaner_發表於2018-11-29

概述

TCP和UDP是網路體系結構TCP/IP模型中傳輸層一層中的兩個不同的通訊協議。

  • TCP:傳輸控制協議,一種面向連線的協議,給使用者程式提供可靠的全雙工的位元組流,TCP套介面是位元組流套介面(stream socket)的一種。
  • UDP:使用者資料包協議。UDP是一種無連線協議。UDP套介面是資料包套介面(datagram socket)的一種。

TCP與UDP簡介

基本TCP客戶—伺服器程式設計基本框架

TCP流程

基本UDP客戶—伺服器程式設計基本框架

UDP流程

UDP和TCP的對比

  • TCP面向連線(三次握手機制),通訊前需要先建立連線;UDP面向無連線,通訊前不需要建立連線;
  • TCP保障可靠傳輸(按序、無差錯、不丟失、不重複、超時重發); UDP不保障可靠傳輸,使用最大努力交付;
  • TCP面向位元組流的傳輸,UDP面向資料包的傳輸。

TCP優缺點:

  • 優點: 
    1.TCP提供以認可的方式顯式地建立和終止連線。 
    2.TCP保證可靠的、順序的(資料包以傳送的順序接收)以及不會重複的資料傳輸。 
    3.TCP處理流控制。 
    4.允許資料優先 
    5.如果資料沒有傳送到,則TCP套介面返回一個出錯狀態條件。 
    6.TCP通過保持連續並將資料塊分成更小的分片來處理大資料塊。—無需程式設計師知道

  • 缺點: TCP在轉移資料時必須建立(並保持)一個連線。這個連線給通訊程式增加了開銷,讓它比UDP速度要慢。

UDP優缺點:

1.UDP不要求保持一個連線 
2.UDP沒有因接收方認可收到資料包(或者當資料包沒有正確抵達而自動重傳)而帶來的開銷。 
3.設計UDP的目的是用於短應用和控制訊息 
4.在一個資料包連線一個資料包的基礎上,UDP要求的網路頻寬比TDP更小。

TCP/IP應用程式設計介面(API)

  • TCP服務端:
  • TCP客戶端:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT  2345
#define DSET_IP_ADDRESS "192.168.218.141"

int main(int argc, char *argv[]) 
{
    int sockfd;
    char buffer[1024];
    struct sockaddr_in server_addr;

    sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sockfd == -1) {
        perror("socket error");
        exit(EXIT_FAILURE);  
    } 

    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family=AF_INET; 
    server_addr.sin_port=htons(PORT); 
    server_addr.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS); 

    if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1) {   
        perror("connect error.");
        exit(EXIT_FAILURE);
    }

    do {
        printf("Please input char:\n"); 
        fgets(buffer,1024,stdin);
        write(sockfd,buffer,strlen(buffer));

    } while (strncmp(buffer, "quit", 4) != 0);

    close(sockfd);

    exit(EXIT_SUCCESS); 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • UDP服務端:
 #include<stdio.h> 
 # include<sys/types.h>
 #include<sys/socket.h>
 #include<netinet/in.h>
 #include<unistd.h>
 #include<errno.h>
 #include<string.h>
 #include<stdlib.h>

 #define SERV_PORT   3000

 int main(int argc, char *argv[])
{
    int sock_fd;   //套接子描述符號
    int recv_num;
    int send_num;
    int client_len;
    char recv_buf[20];
    struct sockaddr_in  addr_serv;
    struct sockaddr_in  addr_client;//伺服器和客戶端地址

    sock_fd = socket(AF_INET,SOCK_DGRAM,0);
    if(sock_fd < 0){
        perror("socket");
        exit(1);
    } else {
         printf("sock sucessful\n");
    }

    //初始化伺服器斷地址
    memset(&addr_serv,0,sizeof(struct sockaddr_in));
    addr_serv.sin_family = AF_INET;//協議族
    addr_serv.sin_port = htons(SERV_PORT);
    addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地址

    client_len = sizeof(struct sockaddr_in);
    /*繫結套接子*/
    if(bind(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr_in))<0 ){
        perror("bind");
        exit(1);
    } else{
        printf("bind sucess\n");
    }

    while(1){
        printf("begin recv:\n");
        recv_num = recvfrom(sock_fd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&addr_client,&client_len);
        if(recv_num <  0){
            printf("bad\n");
            perror("again recvfrom");
            exit(1);
        } else{
            recv_buf[recv_num]='\0';
            printf("recv sucess:%s\n",recv_buf);
        }
        printf("begin send:\n");
        send_num = sendto(sock_fd,recv_buf,recv_num,0,(struct sockaddr *)&addr_client,client_len);
        if(send_num < 0){
            perror("sendto");
            exit(1);
        } else{
            printf("send sucessful\n");
        }
    }
    close(sock_fd);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • UDP客戶端:
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define DEST_PORT 3000
#define DSET_IP_ADDRESS  "192.168.1.103"

int main(int argc, char *argv[])
{
    int sock_fd;/*套接字檔案描述符*/
    int send_num;
    int recv_num;
    int dest_len;
    char send_buf[20]={"hello tiger"};
    char recv_buf[20];
    struct sockaddr_in addr_serv;/*服務端地址,客戶端地址*/

    sock_fd = socket(AF_INET,SOCK_DGRAM,0);//建立套接子
    //初始化伺服器端地址
    memset(&addr_serv,0,sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
    addr_serv.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS);
    addr_serv.sin_port = htons(DEST_PORT);

    dest_len = sizeof(struct sockaddr_in);
    printf("begin send:\n");
    send_num = sendto(sock_fd,send_buf,sizeof(send_buf),0,(struct sockaddr *)&addr_serv,dest_len);
    if(send_num < 0){
        perror("sendto");
        exit(1);
    } else{
        printf("send sucessful:%s\n",send_buf);
    }

    recv_num = recvfrom(sock_fd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&addr_serv,&dest_len);
    if(recv_num <0 ){
        perror("recv_from");
        exit(1);
    } else{
        printf("recv sucessful\n");
        recv_buf[recv_num]='\0';
        printf("the receive:%s\n",recv_buf);
    }

    close(sock_fd);

    return 0;
}

相關文章