Linux网络编程——udp应用教程

tcp与udp的区别:

1.UDP处理的细节比TCP少
2.UDP不能保证消息被传送到目的地
3.UDP不能保证数据包的传递顺序
4.TCP处理UDP不处理的细节
5.UDP是无连接的
6.TCP是保持一个连接
7.UDP只是把数据发送出去而已(像写信一样)

udp应用场景:

1.视频
2.广播(tcp是没有广播功能的)

udp特有函数:

 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                     struct sockaddr *src_addr, socklen_t *addrlen);

注意:addrlen这个参数,一定初始化,int len=sizeof(src_addr);
manpage的资料:

The argument
addrlen is a value-result argument, which the
caller should initialize before the call to the
size of the buffer associated with src_addr, and
modified on return to indicate the actual size of
the source address. The returned address is trun-
cated if the buffer provided is too small; in this
case, addrlen will return a value greater than was
supplied to the call.

 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                const struct sockaddr *dest_addr, socklen_t addrlen);

实例

将上一篇文章filetransfer-tcp改为filetransfer-udp,比较差异

/*
 ============================================================================
 Name        : myfiletransfer-udpt.c
 Author      : Allen
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
#include<stdio.h>
#include<string.h>
 #include <stdlib.h>
#include"pub.h"

int main(int arg ,char*args[])
{
    if(arg<2)
    {
        printf("usage:server port\n");
        return 0;
    }
    int port=atoi(args[1]);
    printf("recving begin\n");

    if((recv_work(port))==1)
    {
        printf("recv success\n");
    }else
    {
        printf("sock disconnect\n");
    }
    return 0;
}
/*
 * client.c
 *
 *  Created on: 2016年10月24日
 *      Author: Administrator
 */

#include<stdio.h>
#include<string.h>
 #include <stdlib.h>
#include"pub.h"

int main(int arg ,char*args[])
{
    if(arg<4)
    {
        printf("usage:client hostname port filename\n");
        return 0;
    }
    int port=atoi(args[2]);
    printf("send begin\n");
    printf("%s send begin\n", args[3]);
    if((send_work(args[1],port,args[3]))==1)
    {
        printf("send success\n");
    }else
    {
        printf("sock disconnect\n");
    }
    return 0;
}
/*
 * pub.h
 *
 *  Created on: 2016年10月24日
 *      Author: Administrator
 */

#ifndef PUB_H_
#define PUB_H_

int send_work(const char*hostname,int port,const char*filename);
int recv_work(int port);

#endif /* PUB_H_ */
/*
 * pub.c
 *
 *  Created on: 2016年10月24日
 *      Author: Administrator
 */

#ifdef WIN
#include <WinSock2.h>
#else
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#define SOCKET int
#endif

#include <stdio.h>
#include "pub.h"

#define MAXBUFSIZE 16384  //16k
void getfilename(const char *filename, char *name) //从完整路径名中解析出文件名称,例如:/home/test/abc.txt,解析完成后为abc.t

{
    int len = strlen(filename);
    int i;
    for (i = (len - 1); i >= 0; i--)
    {
        if ((filename[i] == '\\') || (filename[i] == '/')) //为了兼容linux与windows的路径,同时解析/与\分隔的路径名称
        {
            break;
        }
    }
    strcpy(name, &filename[i + 1]);
    return;
}

SOCKET init_socket() //初始化socket
{
//如果是windows,执行如下代码
#ifdef WIN
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(1, 1);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return -1;
    }

    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }
#endif

    return 0;
}

SOCKET create_recv_socket(int port)
{
    SOCKET st = socket(AF_INET, SOCK_DGRAM, 0); //建立UDPsocket SOCK_DGRAW
    if (st == -1)
    {
        printf("socket failed %s\n", strerror(errno));
        return 0;
    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(st, (struct sockaddr*) &addr, sizeof(addr)) == -1)
    {
        printf("bind failed %s\n", strerror(errno));
        return 0;
    }
    return st;
}

SOCKET create_send_socket()
{
    if (init_socket() == -1)
    {
        return 0;
    }
    SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);
    if (st == -1)
    {
        printf("socket failed %s\n", strerror(errno));
        return 0;
    }
    return st;
}

int send_work(const char*hostname, int port, const char*filename)
{
    SOCKET send_st = create_send_socket();
    if (send_st == 0)
    {
        return 0;
    }
    SOCKET recv_st = create_recv_socket(port); //??为什么port要加1
    if (recv_st == 0)
    {
        return 0;
    }

    FILE*fp = fopen(filename, "rb");
    if (fp == NULL)
    {
        printf("fopen failed %s\n", strerror(errno));
        return 0;
    }
    char *buf = malloc(MAXBUFSIZE);
    memset(buf, 0, MAXBUFSIZE);
    getfilename(filename, buf);

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(hostname);

    size_t rc = sendto(send_st, buf, strlen(buf), 0,
            (struct sockaddr *) &server_addr, sizeof(server_addr));

    if (rc <= 0)
    {
        printf("sendto failed %s\n", strerror(errno));
    } else //发送成功
    {
        struct sockaddr_in client_addr;

        //如果为windows执行如下代码
#ifdef WIN
        int len = 0;
        //如果是linux执行如下代码
#else
        unsigned int len = 0;
#endif
        len = sizeof(client_addr); //??????
        /* The  argument
       addrlen  is  a  value-result  argument,  which  the
       caller  should  initialize  before  the call to the
       size of the buffer associated  with  src_addr,  and
       modified  on  return to indicate the actual size of
       the source address.*/
        memset(&client_addr, 0, sizeof(client_addr));
        memset(buf, 0, MAXBUFSIZE);
        if (recvfrom(recv_st, buf, MAXBUFSIZE, 0,
                (struct sockaddr*) &client_addr, &len) <= 0)
        {
            printf("recvfrom failed %s\n", strerror(errno));
        } else
        {
            if (strncmp(buf, "OK", 2) == 0) //接受来自server端同意发送信号
            {
                while (1)
                {
                    memset(buf, 0, MAXBUFSIZE);
                    rc = fread(buf, 1, MAXBUFSIZE, fp);
                    if (rc <= 0)
                    {
                        break;
                    } else
                    {
                        rc = sendto(send_st, buf, rc, 0,
                                (struct sockaddr *) &server_addr,
                                sizeof(server_addr));
                        if (rc <= 0)
                        {
                            printf("sendto failed %s\n", strerror(errno));
                            break;
                        }
                    }
                }
            }
            memset(buf, 0, MAXBUFSIZE);
            rc = sendto(send_st, buf, 128, 0, (struct sockaddr *) &server_addr,
                    sizeof(server_addr));
        }
    }
    fclose(fp);
    free(buf);

#ifdef WIN
    closesocket(send_st);
    closesocket(send_st);
    WSACleanup();
#else
    close(send_st);
    close(recv_st);
#endif
    return 1;
}

int recv_work(int port)
{
    SOCKET send_st = create_send_socket();
    if (send_st == 0)
    {
        return 0;
    }
    SOCKET recv_st = create_recv_socket(port);
    if (recv_st == 0)
    {
        return 0;
    }

    FILE *fp = NULL;
    char *buf = malloc(MAXBUFSIZE);

#ifdef WIN
    int len = 0;
#else
    unsigned int len = 1;
#endif

    struct sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    memset(buf, 0, MAXBUFSIZE);
    len = sizeof(client_addr); //?????
    size_t rc = recvfrom(recv_st, buf, MAXBUFSIZE, 0,
            (struct sockaddr*) &client_addr, &len);
    if (rc <= 0)
        printf("recvfrom failed %s\n", strerror(errno));
    else
    {
        printf("recving %s\n", buf);
        fp = fopen(buf, "wb");
        if (fp == NULL)
        {
            printf("fopen failed %s\n", strerror(errno));
            return 0;
        }
        memset(buf, 0, MAXBUFSIZE);
        strcpy(buf, "OK");
        client_addr.sin_port = htons(port); //客户端接收数据的端口号为什么要+1???
        rc = sendto(send_st, buf, strlen(buf), 0,
                (struct sockaddr*) &client_addr, sizeof(client_addr));
        if (rc <= 0)
        {
            printf("send to failed %s\n", strerror(errno));
        }
        while (1)
        {
            memset(buf, 0, MAXBUFSIZE);
            rc = recvfrom(recv_st, buf, MAXBUFSIZE, 0,
                    (struct sockaddr*) &client_addr, &len);
            char temp[128];
            memset(temp, 0, sizeof(temp));
            if (memcmp(buf, temp, sizeof(temp)) == 0)
            {
                break;
            }

            if (rc <= 0)
            {
                printf("recvfrom failed %s\n", strerror(errno));
                break;
            } else
            {
                fwrite(buf, 1, rc, fp);
            }
        }
    }

    if (fp)
        fclose(fp);
    free(buf);

#ifdef WIN
    closesocket(send_st);
    closesocket(recv_st);
    WSACleanup();
#else
    close(send_st);
    close(recv_st);
#endif

    return 1;
}

总结:
这里写图片描述
udp使用方法比tcp简单许多,代码与上一篇tcp应用相似,注释就请参考上一篇博文。

在测试过程中,传送一个74M的视频文件,server端没有收到完整的视频文件,这一点证明了udp不能保证数据被传送到目的地,容易丢失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值