首页 > 代码库 > Socket编程实践(13) --UDP编程基础(1)

Socket编程实践(13) --UDP编程基础(1)

UDP特点

    无连接,面向数据报(基于消息,不会粘包)的数据传输服务;

    不可靠(可能会丢包),但一般情况下UDP更加高效;

 
 
UDP客户/服务基本模型



UDP基础API

1.Recvfrom

SYNOPSIS

       #include <sys/types.h>
       #include <sys/socket.h>
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

2.Sendto

SYNOPSIS

       #include <sys/types.h>
       #include <sys/socket.h>
       ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

实践:一个简陋的echo回声server/client

//server.cpp
#include "commen.h"

int main()
{
    //创建UDP socket
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if (sockfd == -1)
    {
        err_exit("socket error");
    }

    //填写server端信息
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9001);
    serverAddr.sin_addr.s_addr =INADDR_ANY;
    //绑定server端端口号
    if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)
    {
        err_exit("bind error");
    }

    char buf[BUFSIZ];
    struct sockaddr_in peerAddr;
    socklen_t peerLen = sizeof(peerAddr);

    while (true)
    {
        memset(buf,0,sizeof(buf));

        int readCount = 0;
        //接收从客户端发送过来的数据
        if ((readCount = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&peerAddr,&peerLen)) == -1)
        {
            err_exit("recvfrom error");
        }
        //打印客户端信息
        cout << "Client: " << endl;
        cout << "\tsin_port: " << ntohs(peerAddr.sin_port) << endl;
        cout << "\tsin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl;

        //将客户端发送来的信息回写回去
        if (sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&peerAddr,peerLen) == -1)
        {
            err_exit("sendto error");
        }

        buf[readCount] = 0;
        //输出到屏幕
        fputs(buf,stdout);
    }

    return 0;
}

//client.cpp
#include "commen.h"

int main()
{
    //创建UDP socket
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if (sockfd == -1)
    {
        err_exit("socket error");
    }

    //填写server端信息
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9001);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    char buf[BUFSIZ];
    //从键盘接收数据
    while (fgets(buf,sizeof(buf),stdin) != NULL)
    {
        //向server端传送数据
        if (sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)
        {
            err_exit("sendto error");
        }

        memset(buf,0,sizeof(buf));
        int readCount = 0;
        //从server端接收数据,并且忽略server端信息recvfrom(xx,xx,xx,xx,NULL,NULL)
        if ((readCount = recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL)) == -1)
        {
            err_exit("recvfrom error");
        }

        buf[readCount] = 0;
        //将数据写到屏幕
        fputs(buf,stdout);
    }

    return 0;
}

实验结果:



查看端口:


-commen.h

#ifndef COMMEN_H_INCLUDED
#define COMMEN_H_INCLUDED

#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/socket.h>

#include <sys/select.h>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <iostream>
using namespace std;

void err_exit(std::string str)
{
    perror(str.c_str());
    exit(EXIT_FAILURE);
}
void peerClosePrint(std::string str = "peer connect closed")
{
    cerr << str << endl;
    _exit(0);
}

#endif // COMMEN_H_INCLUDED

-Makefile

CC = g++ 
CPPFLAGS = -Wall -g -pthread

BIN = server client
SOURCES = $(BIN.=.cpp)

.PHONY: clean all 

all: $(BIN)

clean:
    -rm -rf $(BIN) bin/ obj/ core

Socket编程实践(13) --UDP编程基础(1)