socket编程实战之“基于UDP的聊天小程序”

1.示例描述

按照第一篇文章的框架,使用相应的函数来编写一个基于UDP的socket示例,实现同一台主机不同进程之间的通信(不同主机,修改IP地址即可),基于UDP的socket程序最为核心关键的就是sendto和recvfrom函数。具体表现为:开启两个shell终端运行该程序,A终端可以发送消息给B终端;B终端能够接收到消息并打印出来,同时也可以发送消息给A终端,A终端能显示B终端的响应。
下面分别从“客户端”(先发送消息的)和“服务器端”(先回复,再发送消息的)来实现socket程序。

2.“客户端”

#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>

//宏定义对方IP地址
#define IP "192.168.120.100"

int main(){
    //我方的套接字
    int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        std::cout << "create socket error..." << std::endl;
        return -1;
    }
    
    //注册我方的地址信息
    //如果主机有多张网卡,需要手动分配地址,注册地址信息,表明用来网络传输的是哪张网卡
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("192.168.120.100");
    addr.sin_port = htons(8080);

    //将我方的地址信息(192.168.120.100:8080)绑定到套接字
    if (bind(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
    {
        std::cout << "bind socket error..." << std::endl;
        return -1;
    }

    //输入用户名字
    std::cout << "输入你的名字: ";
    std::string name;
    getline(std::cin, name);

	//数据交互
    while (true)
    {
       	//我方要发送的消息
        std::cout << name << ": ";
        std::string msg;
        //不能换行再发送消息,否则换行之后的消息在下一次调用sendto函数的时候发送
        getline(std::cin, msg);
        if (msg == "拜拜") break;

        //注册对方的地址信息(192.168.120.100:8081)
        sockaddr_in new_addr;
        new_addr.sin_family = AF_INET;
        new_addr.sin_addr.s_addr = inet_addr(IP);
        new_addr.sin_port = htons(8081);
        socklen_t len = sizeof(new_addr);

        //使用sendto函数发送数据,需要知道对方的地址信息
        //使用我方的套接字,将缓冲区的数据发送到通道里(通道另一端的地址需要是已知的)
        int send_size = sendto(sockfd, msg.c_str(), msg.size(), 0, (sockaddr*)&new_addr, len);
        if (send_size == -1)
        {
            std::cout << "send to error..." << std::endl;
            return -1;
        }

        //接收数据,测试:空白的地址也可以接收数据
        sockaddr_in ano_addr;
        socklen_t ano_len = sizeof(ano_addr);
        char buff[BUFSIZ];//开辟缓冲区
        //使用recvfrom函数接收数据,不需要知道对方的地址信息
        int recv_size = recvfrom(sockfd, buff, BUFSIZ, 0, (sockaddr*)&ano_addr, &ano_len);
        if (recv_size == -1)
        {
            std::cout << "recv from error..." << std::endl;
            return -1;
        }
        msg[recv_size] = 0;
        std::cout << "对方: " << msg << std::endl;
    }
    
    //关闭套接字
    close(sockfd);
    return 0;
}

3.“服务器端”

#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>

//宏定义对方IP地址
#define IP "192.168.120.100"

int main(){
    //我方的套接字
    int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        std::cout << "create socket error..." << std::endl;
        return -1;
    }
    
    //注册我方的地址信息
    //如果主机有多张网卡,需要手动分配地址,注册地址信息,表明用来网络传输的是哪张网卡
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("192.168.120.100");
    addr.sin_port = htons(8080);

    //将我方的地址信息(192.168.120.100:8080)绑定到套接字
    if (bind(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
    {
        std::cout << "bind socket error..." << std::endl;
        return -1;
    }

    //输入用户名字
    std::cout << "输入你的名字: ";
    std::string name;
    getline(std::cin, name);

	//数据交互
    while (true)
    {
       	//我方要发送的消息
        std::cout << name << ": ";
        std::string msg;
        //不能换行再发送消息,否则换行之后的消息在下一次调用sendto函数的时候发送
        getline(std::cin, msg);
        if (msg == "拜拜") break;

        //注册对方的地址信息(192.168.120.100:8081)
        sockaddr_in new_addr;
        new_addr.sin_family = AF_INET;
        new_addr.sin_addr.s_addr = inet_addr(IP);
        new_addr.sin_port = htons(8081);
        socklen_t len = sizeof(new_addr);

        //使用sendto函数发送数据,需要知道对方的地址信息
        //使用我方的套接字,将缓冲区的数据发送到通道里(通道另一端的地址需要是已知的)
        int send_size = sendto(sockfd, msg.c_str(), msg.size(), 0, (sockaddr*)&new_addr, len);
        if (send_size == -1)
        {
            std::cout << "send to error..." << std::endl;
            return -1;
        }

        //接收数据,测试:空白的地址也可以接收数据
        sockaddr_in ano_addr;
        socklen_t ano_len = sizeof(ano_addr);
        char buff[BUFSIZ];//开辟缓冲区
        //使用recvfrom函数接收数据,不需要知道对方的地址信息
        int recv_size = recvfrom(sockfd, buff, BUFSIZ, 0, (sockaddr*)&ano_addr, &ano_len);
        if (recv_size == -1)
        {
            std::cout << "recv from error..." << std::endl;
            return -1;
        }
        buff[recv_size] = 0;
        std::cout << "对方: " << buff << std::endl;
    }
    
    //关闭套接字
    close(sockfd);
    return 0;
}

3.效果如下

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值