1. 程式人生 > >網路套接字-----簡單的UDP的實現

網路套接字-----簡單的UDP的實現

背景:

UDP套介面是無連線的、不可靠的資料報協議;既然他不可靠為什麼還要用呢?其一:當應用程式使用廣播或多播時只能使用UDP協議;其二:由於他是無連線的,所以速度快。因為UDP套介面是無連線的,如果一方的資料報丟失,那另一方將無限等待,解決辦法是設定一個超時。

建立UDP套介面時socket函式的第二個引數應該是SOCK_DGRAM,說明是建立一個UDP套介面;由於UDP是無連線的,所以伺服器端並不需要listen或accept函式。

使用UDP套接字程式設計可以實現基於TCP/IP協議的面向無連線的通訊,它分為伺服器端和客戶端兩部分,其主要實現過程如圖所示:
這裡寫圖片描述
程式碼的實現過程:

UDP伺服器

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc,char* argv[])
{
    if(argc<3)
    {
    printf("./server [address] [port]\n");
    exit(EXIT_SUCCESS);
    }
    int sock=socket(AF_INET,SOCK_DGRAM,0
); if(sock<0) { perror("socket"); return 1; } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(atoi(argv[2]));//主機位元組序轉換成網路位元組序 local.sin_addr.s_addr=inet_addr(argv[1]);//點分十進位制的IP地址 //轉換成二進位制的網路位元組序列 //進行繫結埠號 if(bind(sock,(struct sockaddr*)&local,sizeof
(local))<0) { perror("bind"); return 2; } char buf[1024]; struct sockaddr_in client; while(1) { socklen_t len=sizeof(client); ssize_t s = recvfrom(sock,buf,sizeof(buf)-1,0,\ (struct sockaddr*)&client,&len); if(s>0) buf[s]=0; printf("[%s:%d]:%s\n",inet_ntoa(client.sin_addr),\ ntohs(client.sin_port),buf); sendto(sock,buf,strlen(buf),0,\ (struct sockaddr*)&client,sizeof(client)); } }

UDP客戶端:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc,char* argv[])
{
    if(argc<3)
    {
    printf("./server [address] [port]\n");
    exit(EXIT_SUCCESS);
    }
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
    perror("socket");
    return 2;
}

struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[2]));
server.sin_addr.s_addr=inet_addr(argv[1]);

char buf[1024];
struct sockaddr_in peer;
while(1)
{
    socklen_t len=sizeof(peer);
    printf("please enter:  \n");
    fflush(stdout);
    ssize_t s =read(0,buf,sizeof(buf)-1);
    if(s>0)
    {
    buf[s-1]=0;
    sendto(sock,buf,strlen(buf),0,(struct sockaddr*)&server,sizeof(server));
    ssize_t s1=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&peer,&len);
    if(s1>0){
        buf[s1]=0;
        printf("server  echo#  %s\n",buf);
    }
    }
}

}

瞭解涉及到的函式:

1、socket函式
主要執行網路的輸入輸出,一個程序必須做的第一件事就是呼叫socket函式獲得一個檔案描述符:
這裡寫圖片描述

第一個引數指明瞭協議簇,目前支援5種協議簇,最常用的有AF_INET(IPv4協議)和AF_INET6(IPv6協議);第二個引數指明套介面型別,有三種類型可選:SOCK_STREAM(位元組流套介面)、SOCK_DGRAM(資料報套介面)和SOCK_RAW(原始套介面);如果套介面型別不是原始套介面,那麼第三個引數就為0。

2、bind函式
為套介面分配一個本地IP和協議埠,對於網際協議,協議地址是32位IPv4地址或128位IPv6地址與16位的TCP或UDP埠號的組合;如指定埠為0,呼叫bind時核心將選擇一個臨時埠,如果指定一個通配IP地址,則要等到建立連線後核心才選擇一個本地IP地址。
這裡寫圖片描述
bind函式的第一個引數是socket函式返回的套接字介面的檔案描述符,後面的兩個引數分別表示的是用於某種特定協議的地址結構的指標,和指向該地址結構的長度。
3、recvfrom函式
UDP使用recvfrom進行接收資料,在這裡類似於標準的read,不過在這裡recvfrom要寫入目的地址。
這裡寫圖片描述
4、sendto函式
UDP使用的進行發資料的函式,類似於write
這裡寫圖片描述

實現的結果:

最終我們實現在同一個區域網下兩個終端之間的對話。
udp客戶端:
這裡寫圖片描述
udp伺服器:
這裡寫圖片描述