UDP型別的C/S簡單例項
阿新 • • 發佈:2019-02-14
與TCP型別的C/S相比較,UDP缺少了connetc(),listen(),acept()函式,這是用於UDP協議無連線的特性,不用維護TCP的連線,斷開狀態
伺服器端大體的流程為建立套接字,套接字與地址結構進行繫結,收發資料,關閉套接字,分別對應於函式socket(),bind(),sendto()
recvfrom()和close
先建立套接字檔案描述符,使用函式socket(),生成套接字描述符
#include<sys/types.h> #include<sys/socket.h> int socket(int domain,int type,int protocol);
使用者呼叫socket函式,然後這個函式呼叫系統呼叫函式sys_socket(),系統呼叫sys_socket()分為兩部分,一部分生成核心socket結構,另一部分與檔案描述符進行繫結,將繫結的檔案描述符返回。
所以我們可以通過訪問套接字描述符的方式去和核心空間互動
然後第二步就是將套接字描述符與一個地址結構繫結在一起,使用函式bind
#include<sys/types.h> #include<sys/socket.h> int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
與TCP並沒有什麼差異,bind()函式的作用是將一個套接字檔案描述符與一個本地地址繫結在一起,即把傳送資料的埠地址和IP地址進行了指定。
當成繫結之後,就可以使用recvfrom接收資料了
#include<sys/types.h> #include<sys/socket.h> ssize_t recv(int s,void *buf,size_t len,int flags); ssize_t recvfrom(int s,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);
可以看出來recvfrom主要是比recv函式多了一個本地地址結構,所以不需要進行連線,只需要接收時指定傳送方地址就可以
然後下來是我們的客戶端
大體為建立套接字,提取伺服器端地址結構,收發資料
前面兩個步驟上面有提到,主要是發資料的話,要用到sendto()
#include<sys/types.h>
#include<sys/socket.h>
ssize_t send(int s,const void*buf,size_t len,int flags);
ssize_t sendto(int s,const void *buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);
和send主要區別就在於第4個引數,表示接收資料的主機地址資訊,第5個引數為第4個引數所指向內容的長度
具體程式碼如下
伺服器端
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<stdlib.h>
#define BUFF_LEN 256
void udpserv_echo(int s,struct sockaddr *client)
{
int n; //接收資料長度
char buff[BUFF_LEN]; //接收發送緩衝區
socklen_t len; //地址長度
while(1) {
len = sizeof(*client);
n = recvfrom(s,buff,BUFF_LEN,0,client,&len);
sendto(s,buff,n,0,client,len); //將接收到的字元傳送回客戶端
}
}
int main(void)
{
int s; //套接字檔案描述符
struct sockaddr_in local; //本地的地址資訊
struct sockaddr_in from; //傳送方的地址資訊
int from_len = sizeof(from); //地址結構的長度
int n; //接收到的資料長度
char buf[128]; //接受資料緩衝區
s= socket(AF_INET,SOCK_DGRAM,0); //初始化一個IPV4族的資料報套接字
if(-1 == s) {
perror("");
exit(EXIT_FAILURE);
}
local.sin_family = AF_INET;
local.sin_port = htons(8888);
local.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s,(struct sockaddr *)&local,sizeof(local));
udpserv_echo(s,(struct sockaddr *)&from); //回顯處理函式
return 0;
}
客戶端
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#define PORT_SERV 8888
#define BUFF_LEN 256
void udpclie_echo(int s,struct sockaddr *to)
{
char buff[BUFF_LEN];
struct sockaddr_in from;
socklen_t len = sizeof(*to);
sendto(s,buff,BUFF_LEN,0,to,len); //傳送給伺服器
recvfrom(s,buff,BUFF_LEN,0,(struct sockaddr *)&from,&len); //從伺服器接收資料
printf("recved:%s\n",buff);
}
int main(int argc,char *argv[])
{
int s; //檔案描述符
struct sockaddr_in addr_serv; //地址結構
s = socket(AF_INET,SOCK_DGRAM,0); //建立UDP型別套接字
memset(&addr_serv,0,sizeof(addr_serv)); //清空地址結構
addr_serv.sin_family = AF_INET;
addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
addr_serv.sin_port = htons(PORT_SERV); //伺服器埠
udpclie_echo(s,(struct sockaddr *)&addr_serv); //與伺服器互動
close(s);
return 0;
}