網路套接字-----簡單的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伺服器: