【Linux】基于UDP的套接字简单实现

  • ip地址:  ( ipv4)

  1. 功能:唯一标识网络上的主机
  2. 数据:无符号4字节整型uint32_ _t源ip地址->目的ip地址数量: 43亿--不够用
  3. 谁上网给谁分配---dhcp,ip地址替换---NAT,ipv6--ip地址16个字节ipv6并不兼容ipv4套接字编程
  4. 两台主机之间进行网络通信--必定有一方是主动方客户端(主动方) ---请求--->服务器(被动方)
  5. tcp(传输控制协议)---有连接,可靠传输,面向字节流
  6. 确保数据能够到达对端--确保数据的安全传输,传输灵活--传输速率低,粘包问题udp(用户数据报协议)---无连接,不可靠,面向数据报
  7. 无法保证数据的安全传输,传输不太灵活--传输速度快,无粘包问题
  8. 对数据安全性要求高的程序用tcp--文件传输
  9. 对数据的实时性要求高的程序用udp--传视频
  • port端口:

  1. 功能:用于唯一标识主机上处理数据的进程
  2. 数据:无符号2个字节的整数unit16_ t  65535
  3. 源ip,源端口,目的ip,目的端口,协议->(sip, sport, dip, dport, proto)五元组--标识- - -条通信
  • 网络字节序:

  1. 字节序: cpu对数据进行存取的顺序--存取大小大于1个字节的数据
  2. 大端字节序:小端字节序
  3. 通信双方无法确定双方的电脑字节序的时候,发送一个大于一个字节存储的数据就有可能造成数据错误
  4. 解决方法:网络通信统一采取大端字节序
  • socket接口:

  • UdpServer.cc:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include <strings.h>
using namespace std;

//定义一个服务
class UdpServer
{
private:
    int sock;//文件描述符
    string ip;//ip地址
    uint16_t port;//端口号

public:
    UdpServer(string ip_, uint16_t port_):ip(ip_),port(port_)
    {
    }
    //创建套接字
    void InitSever()
    {
        sock = socket(AF_INET, SOCK_DGRAM, 0);
        cout << sock << endl;
        if(sock < 0)
        {
            cerr << "socket error!" << endl;
            exit(2);
        }
        //绑定信息
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port);//端口号转换
        local.sin_addr.s_addr = inet_addr(ip.c_str());
        if(bind(sock, (struct sockaddr*)&local,sizeof(local)) < 0)
        {
            cerr << "bind error!" << endl;
            exit(3);
        }
    }

    //收数据
    void RecvData(string& out, struct sockaddr_in &peer,socklen_t &len)
    {
        char buf[1024];
        ssize_t s = recvfrom(sock, buf, sizeof(buf)-1, 0, (struct sockaddr*)&peer, &len);
        //收数据的信息,放在哪儿,期望放多少,还有收数据的对方的信息
        if(s > 0)
        {
            buf[s] = 0;
            out = buf;
        }
        else
        {
            cerr << "recvfrom error!" << endl;
        }
    }

    //发数据
    void SendData(string &in, struct sockaddr_in &peer, socklen_t len)
    {
        int t = sendto(sock, in.c_str(), in.size(), 0, (struct sockaddr*)&peer, len);//信息从上面的收数据得来
        if(t<0)
        {
            cout << strerror(errno) << endl;
            cout << t <<endl;
            exit(6);
        }
    }

    void Start()
    {
        //不断的读写数据
        string str;
        struct sockaddr_in peer;

        //bzero(&peer, sizeof(peer));

        socklen_t len = 0;
        string suffix = " + UdpServer";

        len  = sizeof(peer);
        while(1)
        {
            cout<<"222"<<endl;
            RecvData(str, peer, len);
            cout<<"i333"<<endl;
            str += suffix;
            cout<<"client# "<<str<<endl;
            SendData(str, peer, len);
           // int t = sendto(sock, str.c_str(), str.size(), 0, (struct sockaddr*)&peer, len);//信息从上面的收数据得来
            cout<<"444"<<endl;
        }
    }

    ~UdpServer()
    {
        close(sock);
    }
};

void Usage(string proc)
{
    cout << "Usage:" << proc << "ip port" << endl;
}

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);
    UdpServer server(ip, port);
    server.InitSever();
    server.Start();
    return 0;
}
  • UdpClient.cc:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;

//定义一个服务
class UdpClient
{
private:
    int sock;//文件描述符 套接字
    string server_ip;//ip地址
    uint16_t server_port;//端口号

public:
    UdpClient(string ip_, uint16_t port_):server_ip(ip_),server_port(port_)
    {
    }

    //创建套接字
    void InitSever()
    {
        sock = socket(AF_INET, SOCK_DGRAM, 0);
        if(sock < 0)
        {
            cerr << "socket error!" << endl;
            exit(2);
        }
        //绑定信息
        //struct sockaddr_in local;
        //local.sin_family = AF_INET;
        //local.sin_port = htons(port);//端口号转换
        //local.sin_addr.s_addr = inet_addr(ip.c_str());
        //
        //if(bind(sock, (struct sockaddr*)&local,sizeof(local)) < 0)
        //{
        //    cerr << "bind error!" << endl;
        //    exit(3);
        //}
    }

    //收数据
    void RecvData(string& out)
    {
        cout<<"555"<<endl;
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        char buf[1024];
        cout<<"7777"<<endl;
        ssize_t s = recvfrom(sock, buf, sizeof(buf)-1, 0, (struct sockaddr*)&peer, &len);
        cout<<"666"<<endl;
        //收数据的信息,放在哪儿,期望放多少,还有收数据的对方的信息
        if(s > 0)
        {
            buf[s] = 0;
            out = buf;
        }
        else
        {
            cerr << "recvfrom error!" << endl;
        }
    }

    //发数据,要知道发给谁
    void SendData(string &in)
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(server_port);//端口号转换     
        server.sin_addr.s_addr = inet_addr(server_ip.c_str());

        int ret=sendto(sock, in.c_str(), in.size(), 0, (struct sockaddr*)&server, sizeof(server));//信息从上面的收数据得来
        if(ret<0)
        {
            cerr<<"sendto error"<<endl;
            exit(4);
        }
    }

    void Start()
    {
        //不断的读写数据
        string str;
        string out;
        while(1)
        {
            cout << "Please Enter# ";
            cin >> str;
            SendData(str);
            cout<<"111"<<endl;
            RecvData(out);
            cout << "server echo# " << out << endl;
        }
    }

    ~UdpClient()
    {
        close(sock);
    }
};

void Usage(string proc)
{
    cout << "Usage:" << proc << "server_ip server_port" << endl;
}

//  ./client server_ip server_port
int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);
    UdpClient client(ip, port);
    client.InitSever();
    client.Start();
    return 0;
}
  •  Makefile:

.PHONY:all
all:client server

client:client.cc
	g++ -o $@ $^
server:server.cc
	g++ -o $@ $^
.PHONY:clean
clean:
	rm -f client server

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值