以udp协议创建通信服务器

概念图

以udp协议创建通信服务器_第1张图片

 创建服务器让A,B主机完成通信。

认识接口

socket

 返回值:套接字,你可以认为类似fd

参数:

  1. domain->:哪种套接字,常用AF_INET(网络套接字)、AF_LOCAL(本地套接字)
  2. type->:发送数据类型,常用 SOCK_DGRAM(以数据报式发送)
  3. protocol->:一般填0,自动推导类型或者IPPROTO_UDP、IPPROTO_TCP。

创建一个套接字,类似创建一个文件标识符fd。

先介绍些结构体类型

struct sockaddr
struct sockaddr_in
struct sockaddr_un

_in结构体中保存的是ip\port数据,而_un中保存的则是本地的数据

以udp协议创建通信服务器_第2张图片

udp协议为了本地通信与网络通信同一套接口兼容,所以先将sockaddr_in/_un强转成sockaddr类型传入各个函数,在函数中判断前2个字节类型,来做本地通信或者网络通信。

bind

将套接字绑定,一般来说套接字绑定都是服务器才会绑定的,客户端一般给操作系统自动分配ip与端口的。

返回值:成功0,失败-1.设置错误码

参数:

  1. sockfd 需要绑定的套接字
  2. sockaddr包含了需要与套接字绑定的ip和端口号。
  3. addrlen该结构体长度。

recvfrom

用来接收数据的接收

返回值:实际接收数据的长度,-1失败

参数

  1. sockfd:将从该套接字的端口和ip中取得数据
  2. buff:输出型参数,将数据存放到buff中。
  3. len:buff的长度
  4. flags:以状态等待数据,一般填0,阻塞等待数据
  5. src_addr:发送方ip+port结构体数据,输出型参数
  6. 结构体数据长度

sendto

发送数据给某个主机

返回值:实际发送数据的个数,-1失败

参数

  1. sockfd:将发送方的ip+port发送给对方
  2. buff:输入型参数,将buff中数据发送给对方。
  3. len:buff的长度;
  4. flags:默认发送方式发送
  5. 接收方ip+port结构体数据,根据该参数寻找对于主机
  6. 结构体数据长度

sockaddr_in结构体配套函数

以udp协议创建通信服务器_第3张图片

机器大小端的转换函数。h本地to转

以太网规定,网络传输数据一定是大端方式传输,所以我们的机器无论是大端还是小端,在网络中都会成为大端序列。

以udp协议创建通信服务器_第4张图片

 当是为了人能看的明白,我们的ip地址一般都是以字符串的方式呈现,这样的方式我们称为点分十进制的方式。而且传入为了的ip地址可能需要改序列,所以一批接口出现了。

以udp协议创建通信服务器_第5张图片

这些接口将字符串转为uint32_t或者将uint32_t转为字符串

代码

一份2个主机通过服务器可以聊天的代码

以udp协议创建通信服务器_第6张图片

服务器代码:

server.hpp

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Log.hpp"
#include 
using std::cin;
using std::cout;
using std::endl;

class udp_server
{
    typedef int socket_t;
    void ip_type()
    {
        cout << "ip:" << _ip << endl;
        if (_ip == "127.0.0.1")
        {
            cout << "#####本地测试#####" << endl;
        }
        else if (_ip.empty())
        {
            cout << "#####开放全部ip地址#####" << endl;
        }
        else
        {
            cout << "#####指定ip地址#####" << endl;
        }
    }
    void init_server()
    {
        _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (_socket < 0)
        {
            Log(FATAL, "socket get fail!!![%d][%s]\n", __LINE__, __TIME__);
            exit(1);
        }
        struct sockaddr_in ip_port;
        bzero(&ip_port, sizeof(ip_port));
        ip_port.sin_family = AF_INET;
        ip_port.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        ip_port.sin_port = htons(_port);
        if (bind(_socket, (struct sockaddr *)&ip_port, sizeof(ip_port)) < 0)
        {
            Log(FATAL, "bind  fail!!![%d][%s]\n", __LINE__, __TIME__);
            exit(2);
        }
        Log(NORMAL, "udp init success!!![%d][%s]\n", __LINE__, __TIME__);
    }

public:
    udp_server(uint16_t port, std::string ip = "") : _ip(ip), _port(port) {}
    udp_server() {}

    void activate()
    {
        init_server();
        ip_type();
        while (1)
        {
            char buff[1024] = {0};
            // cout<<"buff size: "<= 0)
            {
                buff[end] = '\0';
                printf("[%s:%d]clint say# %s\n", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
                sprintf(retbuff,"[%s:%d]clint say# %s", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
            }
            else
            {
                Log(WARINNG, "recvfrom Message have fail [%d][%s]\n", __LINE__, __TIME__);
            }
            //处理数据。
            char key[64];
            snprintf(key,sizeof(key),"%s-%u",inet_ntoa(client_ip_port.sin_addr),client_ip_port.sin_port);
            auto it = _users.find(key);
            if(it==_users.end())
            {
                cout< _users;
};

server.cpp

#include "server.hpp"
#include 
using std::shared_ptr;
void SERVERUER()
{
    std::cout<<"./server + ip + port"< server_ptr(new udp_server(port));
            server_ptr->activate();
        }
        else
        {
            
            in_port_t port=atoi(argv[2]);
            std::string ip=argv[1];
            shared_ptr server_ptr(new udp_server(port,ip));
            server_ptr->activate();
        }
    }
    else
    {
        SERVERUER();
    }
    return 0;
}

客户端代码

client.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Log.hpp"
#include 
using std::cin;
using std::cout;
using std::endl;
typedef int socket_t;

void CLIENTUER()
{
    std::cout << "./client + ip + port" << std::endl;
}

void *thread_func(void *ages)
{
    socket_t *_socket = (socket_t*)ages;
    char get_messages[102];
    struct sockaddr_in temp;
    bzero((void *)&temp, sizeof(temp));
    socklen_t len(sizeof temp);
    while (1)
    {
        ssize_t end = recvfrom(*_socket, get_messages, sizeof(get_messages) - 1, 0, (struct sockaddr *)&temp, &len);
        if (end >= 0)
        {
            get_messages[end] = 0;
            std::cout<< get_messages << std::endl;
        }
    }
    return nullptr;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        CLIENTUER();
        exit(1);
    }
    socket_t _socket = socket(AF_INET, SOCK_DGRAM, 0);
    pthread_t tid;
    pthread_create(&tid,nullptr,thread_func,(void*)&_socket);
    std::string messages;
    struct sockaddr_in server_ip_port;
    bzero(&server_ip_port, sizeof(server_ip_port));
    server_ip_port.sin_family = AF_INET;
    server_ip_port.sin_addr.s_addr = inet_addr(argv[1]);
    server_ip_port.sin_port = htons(atoi(argv[2]));
    socklen_t len = sizeof(server_ip_port);

    while (1)
    {
        fflush(stdout);
        std::getline(std::cin, messages);
        sendto(_socket, messages.c_str(), messages.size(), 0, (struct sockaddr *)&server_ip_port, len);
    }
    return 0;
}

你可能感兴趣的:(udp,服务器,网络协议)