Qt c/C++ 混合编程,windows下的网络编程--udp封装(一)

来源:互联网 发布:广东利为网络和多益 编辑:程序博客网 时间:2024/05/16 06:50

首先说一下.Pro文件myudp.pro

TEMPLATE = appCONFIG += consoleCONFIG -= app_bundleCONFIG -= qtLIBS += -lWs2_32  #表示链接Ws2_32这个库SOURCES += main.cpp \    udp.cHEADERS += \    udp.h

cpp文件main.cpp

实现c和C++的混合编程,以模块化实行,需要单独设计模块,C转到C++主要是调用win底层的库和底层的文件,所以就需要使用win的底层的库文件.pro函数中有对win下库函数的使用LIBS += -lWs2_32,除此之外我们还了解到其实socket是一个封装好的TCP/IP协议,只是函数的个别API,所以不需要知道TCP/IP具体知识

#include <iostream>#include  "udp.h"using namespace std;/********1表示发2表示接收***************/int main(int argc,char *args[])//第一个参数:argc是命令行总的参数个数 //第二参数:args则是输入参数的字符串数组{    if(argc > 1)    {        socket_send(args[1]);//代表IP地址    }      else    {        socket_recv();    }    return 0;}

函数的声明 udp.h文件

#ifndef UDP_H#define UDP_Hextern "C"//一般情况下都是C++来调用C 这是一个关键字{int socket_send(char *IP);int socket_recv();}//这种方式只是为了说明让C++知道这是.c文件的格式,不让C++转换为自己的函数//此外这也是//这样一般的情况下都是C++来调c,所以c适合写底层,而C++适合应用层#endif // UDP_H

c函数模块udp.c

#include <winsock2.h>#include <string.h>#include <stdio.h>int socket_send( char *IP){    //初始化socket    DWORD ver;    WSADATA wsaData;    ver = MAKEWORD(1,1);//在调用WSAStartup的时候告诉win要用什么版本的socket    //unix的socket是内支持的    WSAStartup(ver,&wsaData);//win要求只要使用socket,必须调用这个函数    //初始化socket完成    SOCKET  st = socket(AF_INET,SOCK_DGRAM,0); //这是一个无符号的指针(其实就是文件描述符),移植到Linux就是需要处理这部分的函数                           //socket()建立socket 参数1 使用协议  参数2 套接字类型 参数三为0                           //创建一个文件描述符    struct sockaddr_in addr; //这是一个新结构,在向下兼容的时候,需要将新的结构强转为老模式   memset(&addr,0,sizeof(addr));   addr.sin_family = AF_INET;//指的是IPV4   addr.sin_port = htons(8080);//网络字节序的转换,这是转换的是一个short   addr.sin_addr.s_addr =inet_addr(IP); //调用一个函数将IP地址转换成一个整数   //技巧网络编程的时候要给字节发程序,这是一个环路地址,就是机器给自己发地址   //0 代表自己,255代表广播   //LIBS += -lWs2_32  此处出错是没有链接库的问题 其中-l表示链接库的作用   //   unsigned long laddr = inet_addr("127.0.0.1");   //   unsigned char *p = &laddr;   //如何吧一个字节给读出来,利用的是字符指针   //   printf("%d",sizeof(laddr));   //   printf("%ld,%ld,%ld,%ld\n",*(p),*(p+1),*(p+2),*(p+3));   char buf[1024]={0};//服务器上数据的传输都比较大,所以传输的时候也选择比较大的包   while(1)   {       //发送数据之前讲述是清空       memset(buf,0,sizeof(buf));       gets(buf);//这是从终端读取数据,有什么数据,我就读什么数据      if(buf[0]=='0')          break;//以该数据作为0作为停止发送的条件   //发送数据   size_t send= sendto(st,buf,strlen(buf),0,(struct sockaddr *)&addr,sizeof(addr));//此时发送大小没必要再加1了,受的时候单独处理,第四个参数是flag处理优先级                   //如果第三个参数为1024,会导致发出去的很多数为,由于网络                   //网络带宽的问题而导致网络拥挤,尽可能的包要小,利用最小的包实现资源的利用                   //攻击网络的时候直接可以循环发垃圾包将网络流量耗尽       }            //   closesocket(st);//使用完socket将其关闭   WSACleanup();//释放win socket内部的资源.最好不要让操作系统来处理   return send;}/********发的时候需要地址,但是收的时候就不需要地址了需要的是端口号来处理函数*********/int socket_recv(){    //初始化socket    DWORD ver;    WSADATA wsaData;    ver = MAKEWORD(1,1);//在调用WSAStartup的时候告诉win要用什么版本的socket    //unix的socket是内支持的    WSAStartup(ver,&wsaData);//win要求只要使用socket,必须调用这个函数    //初始化socket完成    SOCKET  st = socket(AF_INET,SOCK_DGRAM,0); //这是一个无符号的指针(其实就是文件描述符),移植到Linux就是需要处理这部分的函数                           //socket()建立socket 参数1 使用协议  参数2 套接字类型 参数三为0                           //创建一个文件描述符    struct sockaddr_in addr; //这是一个新结构,在向下兼容的时候,需要将新的结构强转为老模式   memset(&addr,0,sizeof(addr));   addr.sin_family = AF_INET;//指的是IPV4   addr.sin_port = htons(8080);//网络字节序的转换,这是转换的是一个short   addr.sin_addr.s_addr =htonl(INADDR_ANY);//作为接收方不许要指定的IP地址,IP是个long   int rec = 0;   if(bind(st,(struct sockaddr*)&addr,sizeof(addr))>-1)//在哪个端口收,就要绑定哪个端口号的地址,此外还需要判断是否绑定成功,或者判断是否重复绑定   {       char buf[1024]={0};       struct sockaddr_in sendaddr;//接收方的IP地址       memset(&sendaddr,sizeof(sendaddr),0);       int len = sizeof(sendaddr);       //接收数据       while(1)      {         //接收之前需要将数据清空      memset(buf,0,sizeof(buf));      rec = recvfrom(st,buf,sizeof(buf),0,(struct sockaddr *)&sendaddr,&len);      //该函数是阻塞的,IP这个驱动在网络传输的时候会有一个buff      //通过底层的网线将数据放到buff中,而网络层之上就是传输层,udp/tcp就会从这buff中将数据读出来      //而我们普遍说的socket就是对TCp/ip的一个封装receive就会没有数据的就会等待数据的就收     }   }   closesocket(st);//使用完socket将其关闭   WSACleanup();//释放win socket内部的资源.最好不要让操作系统来处理   return rec;}//win下用nm+可执行程序.exe ,因为变量的名字和函数的名字是标号,所以我们可以用标号来看//在混合编程中C++编译完的函数的名字是变化的,但是注意,C语言编译完的函数名字是不会变的//那问题出来了,问什么C++编译后的名字会变化呢,答案是C++的函数名还需要重载,也就是说C++的函数重载后的函数是完全不同的函数,所以说C++在编译完函数的时候会显示//一长串的字母这样在混合编程中,C++根本就识别不来C语言编译的函数,所以我们会明确的告诉C++这是一个C语言的函数
原创粉丝点击