Linux學習之網路程式設計(UDP程式設計)
言之者無罪,聞之者足以戒。 - “詩序”
前幾篇文章說的都是TCP通訊的問題,這篇文章說一下UDP通訊的相關內容:
下面來看一下基於UDP的獲取時間的客戶伺服器的程式框圖:
(1)、建立一個基於IPv4(AF_INET)的資料報套接字(SOCK_DGRAM)
(2)、ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
(3)、ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
1、從指定地址接收UDP資料報
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
第一個引數:socket的描述符
第二個引數:UDP資料報快取地址
第三個引數:UDP資料報長度
第四個引數:該引數一般為0
第五個引數:傳送端的地址
第六個引數:傳送端的地址長度
返回值:成功則返回接收到的字元數,失敗則返回-1,錯誤原因存於errno中。
2、把UDP資料報發給指定地址
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
第一個引數:socket的描述符
第二個引數:UDP資料報快取地址
第三個引數:UDP資料報長度
第四個引數:該引數一般為0
第五個引數:接收端的地址
第六個引數:接收端的地址長度
返回值:成功則返回實際傳送出去的字元數,失敗返回-1,錯誤原因存於errno 中。
下面看一下伺服器的程式:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define PORT 6666
#define MAXLEN 100
int main()
{
int sockfd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addrlen;
int num;
char buf[MAXLEN];
//建立套接字
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("Creatingsocket failed.");
exit(1);
}
//初始化結構體
bzero(&server,sizeof(server));
server.sin_family=AF_INET;//IPv4
server.sin_port=htons(PORT);//埠號
server.sin_addr.s_addr= htonl (INADDR_ANY);//設定為可以連線任何一個客戶端
//將套接字和伺服器的地址繫結
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("Bind()error.");
exit(1);
}
//得到儲存客戶端的結構體的長度
addrlen=sizeof(client);
while(1)
{
//從客戶端讀取資料,並存儲在buf中
num =recvfrom(sockfd,buf,MAXLEN,0,(struct sockaddr*)&client,&addrlen);
if (num < 0)
{
perror("recvfrom() error\n");
exit(1);
}
//最後一個字元為空(防止打出亂碼)
buf[num] = '\0';
//列印讀取的內容以及ip地址和埠號
printf("You got a message (%s%) from client.\nIt's ip is%s, port is %d.\n"
,buf,inet_ntoa(client.sin_addr),htons(client.sin_port));
//傳送資料到客戶端
sendto(sockfd,"Welcometo client,I am xiaoyi.",32,0,(struct sockaddr *)&client,addrlen);
//判斷接收到的資料是不是bye,是的話就直接退出
if(!strcmp(buf,"bye"))
break;
}
//關閉套接字
close(sockfd);
}
接下來看一下客戶端的程式:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 6666
#define MAXLEN 100
int main(int argc, char *argv[])
{
int sockfd, num;
char buf[MAXLEN];
struct hostent *he;
struct sockaddr_in server,peer;
//判斷輸入的個數
if (argc !=3)
{
printf("Usage: %s <IP Address><message>\n",argv[0]);
exit(1);
}
//返回的是包含主機名的指標
if ((he=gethostbyname(argv[1]))==NULL)
{
printf("gethostbyname()error\n");
exit(1);
}
//建立套接字
if ((sockfd=socket(AF_INET, SOCK_DGRAM,0))==-1)
{
printf("socket() error\n");
exit(1);
}
//初始化結構體
bzero(&server,sizeof(server));
server.sin_family = AF_INET;//IPv4
server.sin_port = htons(PORT);//埠號
// inet_pton(AF_INET,"192.168.177.133",&server.sin_addr.s_addr);
server.sin_addr= *((struct in_addr *)he->h_addr);//ip地址
//向伺服器傳送資料
sendto(sockfd, argv[2],strlen(argv[2]),0,(struct sockaddr *)&server,sizeof(server));
socklen_t addrlen;
//獲取伺服器的結構體長度
addrlen=sizeof(server);
while (1)
{
//從伺服器讀取資料,並存在buf中
if((num=recvfrom(sockfd,buf,MAXLEN,0,(struct sockaddr *)&peer,&addrlen))== -1)
{
printf("recvfrom() error\n");
exit(1);
}
//
if (addrlen != sizeof(server) ||memcmp((const void *)&server, (const void *)&peer,addrlen) != 0)
{
printf("Receive message from otherserver.\n");
continue;
}
//將陣列的最後一位賦值為空
buf[num]='\0';
printf("Server Message:%s\n",buf);
break;
}
close(sockfd);
}
在這裡我說一下程式執行的步驟:
(1)開啟一個終端首先編譯伺服器程式(server)。命令:gcc -o server server.c
(2)執行server程式。命令:./server
(3)開啟另一個終端(開啟終端的快捷鍵CTRL+ALT+T)。編譯客戶端程式(client)。命令:gcc -o client client.c
(4)執行client程式。命令:./client 192.168.177.133 hello
(5)在第二個終端中再次輸入指令:./client 192.168.177.133 bye
觀察兩次執行的結果: