基于UDP的网络编程

  • Post author:
  • Post category:其他


UDP协议(用户数据报协议):

– 传输层协议

– 没有连接

– 不可靠

– 面向数据报

我们先创建一个简易的客户端和服务器。

服务器:

– socket:先创建一个套接字

– bind:将创建的套接字绑定到地址和端口上

– recvfrom:下面就以阻塞的方式等待客户端的数据

客户端:

– socket:先创建一个套接字

– sendto:和服务器进行通信

其中涉及到的函数如下:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>


int socket(int domain, int type, int protocol);
//domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
//type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。
//protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
ssize_t sendto(int sock, void *buff, size_t nbytes, int flags, 
			   struct sockaddr *to, socklen_t addrlen);
//sock:用于传输数据的UDP套接字文件描述符 
//buff:保存待传输数据的缓冲地址值 
//nbytes:待传输的数据长度,以字节为单位 
//flags:可选参数,若没有则传递0 
//to:存有目标地址信息的sockaddr结构体变量的地址值 
//addrlen:传递给参数to的地址值结构体变量长度
ssize_t recvfrom(int sock, void *buff, size_t nbytes, int flags, 
				struct sockaddr *from, socklen_t *addrlen);
//sock:用于接收数据的UDP套接字文件描述符 
//buff:保存接收数据的缓冲地址值 
//nbytes:可接收的最大字节数 
//flags:可选参数,若没有则传入0 
//from:存有发送端地址信息的sockaddr结构体变量的地址值 
//addrlen:保存参数from的结构体变量长度的变量地址值

server.c:

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


int main(int argc,char* argv[])
{
    if(argc != 3)//判断输入的格式
    {
        printf("please enter:[%s,ip,port].\n",argv[0]);
        return 1;
    }
	//创建一个套接字
    int sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock < 0)
    {
        printf("socket error!\n");
        return 2;
    }
	//因为我们采用的IPv4协议,所以得创建一个sockaddr_in的结构体来保存我们服务器的ip和端口信息
    struct sockaddr_in lockal;
    lockal.sin_family = AF_INET;//地址家族
    lockal.sin_port = htons(atoi(argv[2]));//端口号(我们输入的是字符串,所以先转化为数字,然后在从网络转化为本地)
    lockal.sin_addr.s_addr = inet_addr(argv[1]);//(点分十进制转化为四字节的)的ip地址


	//将sock绑定ip和端口号
    if(bind(sock,(struct sockaddr*)&lockal,sizeof(lockal)) < 0)
    {
        printf("bine error!\n");
        return 3;
    }
    
    char buf[1024];
    struct sockaddr_in client;//创建一个保存发送端的地址信息的sockaddr结构体
    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;//将最后一个置为0,这样防止读错
            printf("[%s|%d]: %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
        }
    }
}

client.c:

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


int main(int argc,char* argv[])
{
    if(argc != 3)//判断输入格式是否正确
    {
        printf("please enter:%s,ip,port.\n",argv[0]);
        return(1);
    }
	//创建一个套接字
    int sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock < 0)
    {
        printf("socket error!\n");
        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];
    while(1)
    {
        printf("Please enter:");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf)-1);//从标准输入中读取数据
        if(s > 0)
        {
            buf[s-1] = 0;
            sendto(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&server,sizeof(server));//发送给服务器端
        }
    }
}

效果图:

服务器端:
[kaikai@localhost udp]$ ./server 192.168.43.146 8080
[192.168.43.146|57336]: 123
[192.168.43.146|57336]: 456
[192.168.43.146|57336]: 789
^C
[kaikai@localhost udp]$ 
客户端:
[root@localhost udp]# ./client 192.168.43.146 8080
Please enter:123
Please enter:456
Please enter:789
Please enter:^C                                              
[root@localhost udp]# 

由上面的结果我们可以了解到基于UDP网络编程的基本概念了吧。



版权声明:本文为q496958148原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。