重明鸟软件知识平台
@网络编程:UDP
UDP是无连接的基于数据报的传输方式,其特点是速度快,数据发送后就不用管了。所以不能保证数据到达目的地的顺序和是否能到达。UDP是不用连接的,只要在发送时填上服务器的IP和端口就行了。而服务端也不用Listen监听是否有人来链接,他只是用recvfrom来接收来自客户端所传来的信息。UDP适合在局域网内使用。

下面的Client向Server发送Hello!这6个字符,Server收到后会输出该Client的IP,并回发HELLO!全大写6个字符给Client。

我们把实现UDP功能的函数加入到上一节课中的NClient和NServer类中去。方便调用。

NClient类中加入的函数:
bool InitUdpClient()
{
    if(false==TestVersion())
        return false;
    //初始化socket为UDP模式
    m_ClientSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(m_ClientSocket == -1)
    return false;
    isTcp = false;
    return true;
}
  
/*
发送字符串给远程计算机,保证所以字符都能成功发送。
*/
bool SendUdpMsg(const char* IP,int port,const char* str)
{
    int sendlen = 0;
    int len = strlen(str);
    SOCKADDR_IN m_addr;
    //使用INET协议族
    m_addr.sin_family = AF_INET;
    //设置要链接远程计算机的IP
    m_addr.sin_addr.S_un.S_addr = inet_addr(IP);
    //htons将主机字节变为网络字节
    m_addr.sin_port = htons(port);
    int m_addrlen = sizeof(m_addr);
    while(len>0)
    {
        //udp用sendto,前四个参数跟TCP一样。
        //后两个参数是tcp里connect里的服务器地址信息
        sendlen = sendto(m_ClientSocket,&(str[sendlen]),len,0,
                    (struct sockaddr*)&m_addr,m_addrlen);
        if(sendlen == SOCKET_ERROR)
        {
            closesocket(m_ClientSocket);
            return false;
        }
        len -= sendlen;
    }
    return true;
}
  
/*
从远程计算机接收字符串,保证所以字符都能成功接送。
*/
bool RecvUdpMsg(char* str,int len)
{
    int recvlen = 0;
    int oldlen = len;
    SOCKADDR_IN m_addr;
    int m_addrlen = sizeof(m_addr);
    while(len>0)
    {
        //如果不关心服务器信息,最后两个参数可以用NULL
        recvlen = recvfrom(m_ClientSocket,&(str[recvlen]),len,0,
                    (struct sockaddr*)&m_addr,&m_addrlen);
        if(recvlen == SOCKET_ERROR)
        {
            closesocket(m_ClientSocket);
            return false;
        }
        len -= recvlen;
    }
    //字符串终结符
    str[oldlen]="";
    return true;
}


NServer类中加入的函数:

bool StartUdpServer(int port)
{
    /*
    创建基于UDP的socket
    */
    m_ServerSocket = socket(AF_INET,SOCK_DGRAM,0);
    if(m_ServerSocket == -1)
    {
        return false;
    }
  
    struct sockaddr_in m_addr;
    /*
    使用INET协议族,本机地址。并设置监听端口号,跟TCP一样。
    */
    m_addr.sin_family = AF_INET;
    m_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    m_addr.sin_port = htons(port);
    int addr_len = sizeof(m_addr);
  
    //绑定socket
    if(-1 == bind(m_ServerSocket,(struct sockaddr*)&m_addr,addr_len))
    {
        close(m_ServerSocket);
        return false;
    }
  
    while(true)
    {
        struct sockaddr_in client_address;
        unsigned int address_len = 0;
        address_len = sizeof(client_address);
        recvfrom(m_ServerSocket,r_msg,strlen(r_msg),0,(
        struct sockaddr*)&client_address,&address_len);
        //输出请求链接的客户端IP地址
        printf("------------------\n");
        printf("client ip:%s\n",inet_ntoa(client_address.sin_addr));
  
        //输出客户端发来的信息。
        r_msg[m_Len]="";
        printf("recv msg:%s\n",r_msg);
        //向客户端发送信息。
        sendto(m_ServerSocket, r_msg,strlen(r_msg),0,
                (struct sockaddr*)&client_address,address_len);
  
        close(m_ServerSocket);
        return true;
    }
    return true;
}


Client源程序:

#include<stdio.h>
#include<conio.h>
#include "NClient.cpp"
int main()
{
    NClient* m_Client = new NClient();
    if(false == m_Client->InitUdpClient())
    {
        printf("Init UDP Client error!\n");
        getch();
        return 0;
    }
  
    char msg[6];
    if(false==m_Client->SendUdpMsg("192.168.1.102",10001,"Hello!"))
    {
        printf("Send error!\n");
    }
  
    m_Client->RecvUdpMsg(msg,6);
    printf("recv:%s\n",msg,strlen(msg));
    getch();
    return 0;
}


Server源程序:
#include <iostream>
#include "NServer.cpp"
using namespace std;
int main()
{
    NServer* m_Server = new NServer;
    m_Server->SetCharLen(6);
    if(m_Server->StartUdpServer(10001)==false)
    cout << "Start UdppServer error!" << endl;
    cout<<"UdpServer is Stop!"<<endl;
    return 0;
}
两个程序进行测试,先运行Server程序,再运行Client程序。
运行结果:
Server运算结果:
client ip:192.168.1.100
recv msg:Hello!
UdpServer is Stop!

Client运算结果:
recv:HELLO!
@站内查找
@栏目文章
【基础教程】TKinter(5):Label控件
【基础教程】TKinter(4):Messagebox控件
【基础教程】TKinter(3):Button控件
【基础教程】TKinter(2):控件及其属性
【基础教程】TKinter(1):第一个tkinter程序
【基础教程】Python守护进程创建
【基础教程】PyGame(13):三维环境设置
【基础教程】C/C++指针函数和回调函数
【基础教程】C/C++多进程编程(3)
【基础教程】C/C++多进程编程(2)
【基础教程】C/C++多进程编程(1)
【基础教程】C/C++多线程编程(2)
【基础教程】C/C++多线程编程(1)
【基础教程】C/C++动态库编程
【基础教程】C/C++静态库编程
【基础教程】photoshop图片混合公式
【基础教程】PyGame(12):旋转和缩放
【基础教程】PyGame(11):Surface操作
【基础教程】网络编程:Epoll(2)
【基础教程】网络编程:Epoll(1)
【基础教程】网络编程:IOCP(3)
【基础教程】网络编程:IOCP(2)
【基础教程】网络编程:IOCP(1)
【基础教程】网络编程:UDP
【基础教程】网络编程:TCP
【基础教程】Ubuntu安装Hadoop(4)
【基础教程】Ubuntu安装Hadoop(3)
【基础教程】Ubuntu安装Hadoop(2)
【基础教程】Ubuntu安装Hadoop(1)
【基础教程】Hadoop技术原理
【基础教程】Hadoop基本命令
【基础教程】Hadoop是什么东西
【基础教程】排序算法介绍
【基础教程】PyGame(10):声音控制
【基础教程】PyGame(9):鼠标事件(2)
【基础教程】PyGame(8):鼠标事件(1)
【基础教程】PyGame(7):键盘事件(2)
【基础教程】PyGame(6):键盘事件(1)
【基础教程】PyGame(5):显示图片
【基础教程】PyGame(4):显示文字
【基础教程】PyGame(3):图元绘制
【基础教程】PyGame(2):游戏框架
【基础教程】PyGame(1):开发环境搭建
【基础教程】Python(10):类定义
【基础教程】Python(9):自定义模块
【基础教程】Python(8):输入输出控制
【基础教程】Python(7):函数定义
【基础教程】Python(6):中断语句
【基础教程】Python(5):判断语句
【基础教程】Python(4):循环语句
【基础教程】Python(3):变量与运算符
【基础教程】Python(2):Hello
【基础教程】Python(1):介绍与安装
Copyright @ 2011-2018 by szc  桂ICP备11003301号-1  桂公网安备45040302000027号  Email:szcsoft@qq.com