网络套接字-----简单的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服务器:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/daboluo521/article/details/80483835
今日推荐