跨平台网络编程

myudp - 源码文件 - 点击下载

udp.h

//C++为了实现函数的重载,在编译的时候要将函数名进行重命名
//C没有函数重载,所以不会在编译的时候带对函数名进行重命名
//所以在C++中如果要使用C的函数,需要明确的告诉编译器,这是一个C的函数,不要对其进行重命名
//使用exten "C"关键字来实现
//extern "C"
//{
//int socket_send(const char *IP);
//int socket_recv();
//}
int socket_send(const char *IP);
int socket_recv();

udp.cpp

#include <string.h>
#include <stdio.h>
 
#ifdef MYLINUX
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define SOCKET int
#else
#include <winsock2.h>
#endif
 
//使用socket发消息
int socket_send(const char *IP)
{
#ifndef MYLINUX
    //初始化socket
    DWORD ver;
    WSADATA wsaData;
    //在调用WSAStatrtup要告诉windows我们要用什么版本的socket
    ver = MAKEWORD(1,1);
 
    //windows要求,只要用socket,第一步就要调用这个函数
    WSAStartup(ver,&wsaData);
    //-----初始化完成-----//
#endif
    //建立一个socket
    //第一个参数是指定socket要用那个协议,AF_INET代表要用TCP/IP协议
    //第二个参数SOCK_DGRAM意思是要用UDP协议
    //第三个参数一般默认填0
    //SOCKET就是一个指向无符号整数的指针
    SOCKET st = socket(AF_INET,SOCK_DGRAM,0);
 
    /*
    struct sockaddr_in {
        short sin_family;       //代表我要指向一个什么协议的地址
        u_short sin_port;         //端口号
        struct in_addr sin_addr; //IP地址
        char sin_zero[8];      //这是为了兼容老结构sockaddr的字节长度,在sendto()函数中使用的还是老结构sockaddr
    };
    //*/
    struct sockaddr_in addr;
 
    //初始化结构体
    memset(&addr,0,sizeof(addr));
 
    //代表要使用一个TCP/IP的地址
    addr.sin_family = AF_INET;
 
    //htons = host to net short
    //htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。
    addr.sin_port = htons(8080);
 
    //s_addr = unsigned long
    //inet_addr()可以将一个字符串的ip地址转化成一个整数
    //首先给自己发消息,如果发生错误,可以检查是网络问题还是自己代码的问题
    //科普:在一个ip地址中,0 代表自己,255 代表广播
    addr.sin_addr.s_addr = inet_addr(IP);
 
    //inet_addr转换原理
    //unsigned long laddr = inet_addr("192.168.6.200");
    //unsigned char *p = &laddr;
    //printf("%u,%u,%u,%u\n",*(p),*(p+1),*(p+2),*(p+3));
 
    char buf[1024] = {0};
    size_t rc;
    while(1){
        memset(buf,0,sizeof(buf));
        scanf("%s",&buf);
        if(buf[0] == '0'){
            break;
        }
        //发送udp的数据
        //网络编程原理:尽可能用小的数据包实现大的功能
        //这里如果使用sizeof() = 1024,会浪费带宽,所以使用strlen
        //第一个参数是socket
        //第二个参数是数据包
        //第三个参数是将要发送的长度
        //第四个参数是优先级
        //第五个参数是IP地址结构体的地址
        //第六个参数是IP地址结构体的长度
        //函数返回值size_t代表发送了多少内容出去
        //说明:在sendto中第五个参数是IP地址结构体的地址,使用的还是老的IP地址结构体sockaddr,但是我们现在为了方便,都是使用新的IP地址结构体sockaddr_in,所以在使用sendto时还需要将新的IP地址结构体sockaddr_in强制转化为老的IP地址结构体sockaddr
        rc = sendto(st,buf,strlen(buf),0,(struct sockaddr *)&addr,sizeof(addr));
    }
#ifdef MYLINUX
    close(st);//使用完socket要将其关闭
#else
    //使用完成后需要将socket进行关闭
    closesocket(st);
    //释放win socket内部的相关资源
    WSACleanup();
#endif
    return rc;
}
 
int socket_recv()
{
#ifndef MYLINUX
    DWORD ver;
    WSADATA wsaData;
    ver = MAKEWORD(1,1);
    WSAStartup(ver,&wsaData);
#endif
    SOCKET st = socket(AF_INET,SOCK_DGRAM,0);
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
 
    //作为接受方,不要指定具体的ip地址,接收的ip就是程序运行主机的ip,在多网卡的情况下才可能需要写
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
    int rc = 0;
    //bind()将端口号和程序进行绑定,对于操作系统来讲,需要避免两个程序绑定同一个端口号
    //第一个参数是socket
    //第二个参数是IP地址结构体的地址
    //第三个参数是IP地址结构体的长度
    //如果bind()返回 -1,这说明这个端口已经被人使用了,绑定失败
    if(bind(st,(struct sockaddr *)&addr,sizeof(addr)) != -1){
        char buf[1024] = {0};
        struct sockaddr_in sendaddr;
        memset(&sendaddr,0,sizeof(sendaddr));
#ifdef MYLINUX
        socklen_t len;
#else
        int len;
#endif
        len = sizeof(sendaddr);
        while(1){
            memset(buf,0,sizeof(buf));
            //接收upd的数据
            //阻塞,一个函数在没有返回之前,程序被挂起
            //recvfrom 就是一个阻塞的函数
            //recvfrom 阻塞原理
            //|--------------------------------------------------|
            //|socket,recvfrom - 从底层接收的buffer读取数据,当接收的buffer没有数据时,recvfrom就在死等,这就是阻塞
            //|--------------------------------------------------|
            //|UDP,TCP
            //|--------------------------------------------------|
            //|IP,缓存区buffer,如果有数据进来,将会被存储在这个区域
            //|--------------------------------------------------|
            //|底层硬件
            //|--------------------------------------------------|
            rc = recvfrom(st,buf,sizeof(buf),0,(struct sockaddr *)&sendaddr,&len);
            printf("%s-->%s\n",inet_ntoa(sendaddr.sin_addr),buf);
        }
    }
 
#ifdef MYLINUX
    close(st);//使用完socket要将其关闭
#else
    //不管端口绑定是成功还是失败,最后都要将资源进行释放
    closesocket(st);
    WSACleanup();
#endif
 
    return rc;
}

main.cpp

#include "udp.h"
#ifndef MYLINUX
#include <iostream>
#endif
//#include "basic.h"
using namespace std;
int main(int argc,char *args[])
{
    if(argc > 1){
        socket_send(args[1]);
    }
    else{
        socket_recv();
    }
    return 0;
}

window下需要myudp.pro文件

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
#-lWs2_32,link Ws2_32.lib
LIBS += -lWs2_32
SOURCES += \
        main.cpp \
    udp.cpp \
    basic.cpp
HEADERS += \
    udp.h \
    basic.h

linux下需要makefile文件

CC=g++

CFLAGS=-DMYLINUX

SRCS=main.cpp\
    basic.cpp\
    udp.cpp

OBJS=$(SRCS:.cpp=.o)

EXEC=myapp

start: $(OBJS)
    $(CC) -o $(EXEC) $(OBJS)

.cpp.o:
    $(CC) -o $@ -c $< $(CFLAGS)

clean:
    rm -rf $(OBJS)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值