简单的UDP网络程序

下面是我的另外一篇文章TCP协议和UDP协议的区别:
https://blog.csdn.net/qq_37941471/article/details/80888827
这样我们可以更清楚的理解程序

这里写图片描述

UDP服务器和客户端实现需要的接口:

下面介绍的接口都在这个头文件中:

#include <sys/socket.h>
#include <sys/types.h>

1. 创建套接字 ( socket() )

int socket(int domain, int type, int protocol);

int socket(int domain, int type, int protocol);  
  1.domain 指定使用何种的地址类型
      协议                  说明
    PF_INET/AF_INET Ipv4   网络协议
    PF_INET6/AF_INET6      Ipv6 网络协议
  2. type的类别。见表:
    类型            说明
    SOCK_STREAM 提供双向连续且可信赖的数据流, 即TCP
    SOCK_DGRAM  使用不连续不可信赖的数据包连接,即UDP
  3. protocol 用来指定socket 所使用的传输协议编号,通常为0
  4.返回值:成功(0);失败(-1)
  5. socket()打开一个网络通讯接口,如果成功的话,就想open()一样返回一个文件描述符

2. 命名套接字

//2. 命名套接字

    struct sockaddr_in local;
    local.sin_family = AF_INET;//Ipv4: AF_INET;Ipv6: AF_INET6
    local.sin_port = htons(atoi(argv[2]));//端口号是2位的数
    local.sin_addr.s_addr = inet_addr(argv[1]);

3. 绑定端口号 ( bind() )

int bind(int sockfd, struct sockaddr * my_addr, int addrlen);

int bind(int sockfd, struct sockaddr * my_addr, int addrlen);  
  1. 返回值:成功(0);失败(-1)
  2. 作用:将参数sockfd和myaddr绑定在一起
  3. struct sockaddr * :是一个通用的结构体

4. 接受消息 ( recevfrom() )

 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);////后面两个参数是 输出型参数

5. 发送消息 ( sento() )

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
              const struct sockaddr *dest_addr, socklen_t addrlen);
函数说明:
    sendto() 用来将数据由指定的socket 传给对方主机. 

代码实现:


创建下面的文件:

Makefile udp_server.c udp_client.c

Makefile:

.PHONY:all clean                                                                                                                                                  
all:udp_server udp_client
udp_server:udp_server.c
        gcc $^ -o $@
udp_client:udp_client.c
        gcc $^ -o $@

clean:
        rm -rf udp_server udp_client

udp_server.c

#include <stdio.h>                                                                                                                                                
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>


int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        printf("Usage:%s ip port\n",argv[0]);
        return 1;
    }

    //1. 创建套接字

    int sock = socket(AF_INET, SOCK_DGRAM , 0 );// SOCK_DGRAM 表示UDP
    if(sock < 0)
    {
        perror("socket");
        return 2;
    }
    printf("Socker:%d\n",sock);


    //2. 命名套接字

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[2]));//端口号是2位的数
    local.sin_addr.s_addr = inet_addr(argv[1]);

    //3. 绑定端口号
    if( bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0  )
    {
        perror("bind");
        return 3;
    }

    char buf[1024];//缓冲区

    //4. 服务器接收客户信息

    while(1)
    {
        struct sockaddr_in client;

        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));
        }
    }

    close(sock);
    return 0;
}

udp_client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>


int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        printf("Usage:%s ip port\n",argv[0]); 
        return 1;
    }

    //1. 创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM , 0 );// SOCK_DGRAM 表示UDP
    if(sock < 0)
    {
        perror("socket");
        return 2;
    }

    printf("sock:%d\n",sock);

  //2. 命名套接字

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));//端口号是2位的数
    server.sin_addr.s_addr = inet_addr(argv[1]);

    //3. 客户端尽量不绑定端口号
    char buf[1024];//缓冲区

    //4. 客户端发送信息

    while(1)
    {
        printf("Please Enter# ");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf)-1);//-1是为了去掉‘/0’
        if( s > 0 )
        {
            buf[s-1] = 0;
            sendto( sock, buf, strlen(buf) , 0 , (struct sockaddr*)&server, sizeof(server));
            ssize_t _s = recvfrom(sock,buf,sizeof(buf)-1,0,NULL,NULL);
            if(_s > 0)
            {
                buf[_s] = 0;
                printf("server echo# %s\n",buf);
            }
        }
    }

    close(sock);//最后记得关闭sock,因为文件描述符也会有文件描述符泄漏
    return 0;
}

测试代码:


1. 先编译运行服务器

这里写图片描述

2. 再编译运行客户端,并向服务器发送消息

这里写图片描述

3. 服务器接收信息

这里写图片描述

4. 按ctrl+c,结束客户端进程

5. 服务器一直等待接受信息,直到又打开一个客户端,然后向服务器发送消息或者按ctrl+c将服务器的进程也结束

5. 分别按ctrl+c结束客户端进程和服务器进程

这里写图片描述
这里写图片描述

另外,我们可以在同一网段和别的ip去建立连接:

下面是TCP服务器和客户端连接的例子,但是UDP连接的方式和这个相同:


一. 先去ping 别人的ip,下面就是成功的信息:
这里写图片描述

二. 再去向别人发送客户端的可执行文件:192.168.31.209 是对方的ip地址,:/home是把可执行文件发到对方的home目录下,最底下是输入对方的密码

这里写图片描述

三. 自己去运行服务器端:
192.168.31.32是我自己的ip地址,8080是绑定的端口

./Tcp_server 192.168.31.32 8080

四. 别人运行客户端:
ip地址和端口同服务器的

./Tcp_client 192.168.31.32 8080

猜你喜欢

转载自blog.csdn.net/qq_37941471/article/details/80726398