3.SDL2_net TCP服务器端和多个客户端 续

上一节缺少了tcputil的讲解,首先这几个函数都不是我写的,一部分是从SDL_net官网上下载的小例子,另一部分是找的github上的代码。

tcputil.h

#ifndef tcputil_h
#define tcputil_h 1

#ifdef WIN32
#else
        #include <sys/socket.h>
        #include <sys/ioctl.h>
        #include <net/if.h>
        #include <arpa/inet.h>
#endif

#include <string>

#include "SDL.h"
#include "SDL_net.h"

/* receive a buffer from a TCP socket with error checking */
/* this function handles the memory, so it can't use any [] arrays */
/* returns 0 on any errors, or a valid char* on success */
extern char *getMsg(TCPsocket sock, char **buf);

/* send a string buffer over a TCP socket with error checking */
/* returns 0 on any errors, length sent on success */
extern int putMsg(TCPsocket sock, const char *buf);
/**
 * 获取当前的IP地址
 * @param num_ip ip的数字
 * @return 格式化的ip地址
 */
extern std::string getLocalHostIP(Uint32& num_ip);

#endif

putMsg负责发送信息,getMsg负责接收信息,新加的getLocalHostIP()则负责获取当前主机的IP地址,这个函数在局域网游戏中尤其有用,比如局域网对战,该函数仅仅在ubuntu下测试成功,暂时未在window下测试。

#include "tcputil.h"

char *getMsg(TCPsocket sock, char **buf)
{
        Uint32 len,result;
        static char *_buf;

        /* allow for a NULL buf, use a static internal one... */
        if(!buf)
                buf=&_buf;
    
        /* free the old buffer */
        if(*buf)
                free(*buf);
        *buf=NULL;

        /* receive the length of the string message */
        result=SDLNet_TCP_Recv(sock,&len,sizeof(len));
        if(result<sizeof(len))
        {
                if(SDLNet_GetError() && strlen(SDLNet_GetError())) /* sometimes blank! */
                        printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
                return(NULL);
        }
    
        /* swap byte order to our local order */
        len=SDL_SwapBE32(len);
    
        /* check if anything is strange, like a zero length buffer */
        if(!len)
                return(NULL);

        /* allocate the buffer memory */
        *buf=(char*)malloc(len);
        if(!(*buf))
                return(NULL);

        /* get the string buffer over the socket */
        result=SDLNet_TCP_Recv(sock,*buf,len);
        if(result<len)
        {
                if(SDLNet_GetError() && strlen(SDLNet_GetError())) /* sometimes blank! */
                        printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
                free(*buf);
                buf=NULL;
        }

        /* return the new buffer */
        return(*buf);
}

getMsg负责获取数据,这一对函数必须配套使用,因为putMsg函数在发送真正的信息之前,会先发送本次要发送的字节数,而getMsg也会先获取字节数,并分配好适当的空间。另外,getMsg()内部采取了静态局部变量来设置内存,因此,不必担心内存问题。

int putMsg(TCPsocket sock,const char *buf)
{
        Uint32 len,result;

        if(!buf || !strlen(buf))
                return(1);

        /* determine the length of the string */
        len=strlen(buf)+1; /* add one for the terminating NULL */

        /* change endianness to network order */
        len=SDL_SwapBE32(len);

        /* send the length of the string */
        result=SDLNet_TCP_Send(sock,&len,sizeof(len));
        if(result<sizeof(len)) {
                if(SDLNet_GetError() && strlen(SDLNet_GetError())) /* sometimes blank! */
                        printf("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
                return(0);
        }

        /* revert to our local byte order */
        len=SDL_SwapBE32(len);

        /* send the buffer, with the NULL as well */
        result=SDLNet_TCP_Send(sock,buf,len);
        if(result<len) {
                if(SDLNet_GetError() && strlen(SDLNet_GetError())) /* sometimes blank! */
                        printf("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
                return(0);
        }

        /* return the length sent */
        return(result);
}

putMsg和getMsg函数相对,putMsg主要是向套接字发送数据。

std::string getLocalHostIP(Uint32& num_ip)
{
#ifdef WIN32
        char text[20] = {};
        IPaddress localhost_ip;
        SDLNet_ResolveHost(&localhost_ip, nullptr, 0);
        SDLNet_ResolveHost(&localhost_ip, SDLNet_ResolveIP(&localhost_ip), 0);
        //output
        num_ip = SDL_SwapBE32(localhost_ip.host);
        sprintf(text, "%d.%d.%d.%d",
                        num_ip>>24,
                        (num_ip>>16) & 0xff,
                        (num_ip>>8) & 0xff,
                        (num_ip & 0xff));
        return std::string(text);
#else
        std::string ip;
        int socket_fd = socket(PF_INET,SOCK_DGRAM,0);
        struct sockaddr_in *sin;
        ifconf conf;
        struct ifreq* ifr;
        char buf[128];
        int i,n;
        conf.ifc_len = 128;
        conf.ifc_buf = buf;
        ioctl(socket_fd,SIOCGIFCONF,&conf);
        ifr = conf.ifc_req;
        n = conf.ifc_len/sizeof(struct ifreq);
        for(i=0;i<n;i++)
        {
                sin = (struct sockaddr_in*)(&ifr->ifr_addr);
                ip = inet_ntoa(sin->sin_addr);
                if(ip.compare("127.0.0.1"))
                {
                        return ip;
                }
                ifr++;
        }
        ip = "127.0.0.1";
        return ip;
#endif
}

最后则是getLocaHostIP()这个函数,此函数是我在sdlgui贴吧里找到的一部分代码,该代码作者目前不再进行维护,不过有的代码还是可圈可点的(我不懂socket编程,我只是大自然的搬运工)。

本节结束。

SDL_net 官方链接:http://www.libsdl.org/projects/SDL_net/docs/index.html

sdl_gui github链接:https://github.com/SDLGUI/SDLGUI

猜你喜欢

转载自blog.csdn.net/bull521/article/details/84494637
今日推荐