搜索

首页  >  问答  >  正文

c++ - 用C语言socket登入斗鱼弹幕服务器的问题

根据斗鱼给的开发者手册,用struct构建出应用层协议头,发送登入请求,建立连接成功但没有从服务器传回有效消息。
代码不长,边学socket边写的注释。
抓包显示成功的建立了连接,图片放在最后。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<code>#include <stdio.h>

#include <stdlib.h>

#include <winsock2.h>

#pragma comment (lib, "ws2_32.lib")

char* getIP() {

    struct hostent *host = gethostbyname("openbarrage.douyutv.com");

    if (!host) {

        printf("Get ip error\n");

        system("pause");

        exit(0);

    }

    return inet_ntoa(*(struct in_addr*)host->h_addr_list[0]);

}

 

struct postData{

    int data_len;//4字节

    int data_len_2;//4字节

    short message = 689;//2字节

    char secreat = 0;//1字节

    char presv = 0;//1字节

    char body[31] = "type@=loginreq/roomid@=846805/";

};

int main() {

    WSADATA wsaData;

    WSAStartup(MAKEWORD(2, 2), &wsaData); //初始化

    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建socket

 

    //SOCKADDR为通用结构体,同时处理IPv4和IPv6

    //sockaddr_in为IPv4的结构体 sockaddr_in6为IPv6的结构体

    //SOCKADDR中IP地址和端口在一起,强制转换类型时转换

    sockaddr_in sockAddr;

    memset(&sockAddr, 0, sizeof(sockAddr));

    sockAddr.sin_family = PF_INET; //类型:IPv4

    sockAddr.sin_addr.s_addr = inet_addr("123.150.206.162");//getIP()返回

    /*

        sin_addr为结构体

        struct in_addr{

        in_addr_t  s_addr;  //32位的IP地址

    };

    */

    sockAddr.sin_port = htons(8601);

 

    connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));

     

    postData post_Data;

    post_Data.data_len = sizeof(post_Data);

    post_Data.data_len_2 = sizeof(post_Data);

    send(sock, (char*)&post_Data, sizeof(postData), 0);

    printf("发送成功,接收中");

    char bufRec[10000];

    recv(sock, bufRec, sizeof(bufRec), 0);

    printf("Message form server: %s\n", bufRec);

 

    closesocket(sock);

    //终止使用 DLL

    WSACleanup();

    system("pause");

    return 0;

}</code>


协议组成 众所周知,受 TPC 最大传输单元(MTU)限制及连包机制影响,应用层协
议需自己设计协议头,以保证丌同消息的隔离性和消息完整性。斗鱼后台协议头 设计如下:

登录请求消息 该消息用于完成登陆授权,完整的数据部分应包含的字段如下: type@=loginreq/roomid@=301712/
字段说明 type 表示为“登陆请求”消息,固定为 loginreq roomid 所登录房间的 ID

服务端消息格式 服务端端向客户端发送消息时,头部消息类型字段为 690。
2.4.1 登录响应消息 服务端返回登陆响应消息,完整的数据部分应包含的字段如下: type@=loginres/userid@=0/roomgroup@=0/pg@=0/sessionid@=0/us
ername@=/nickname@=/is_signined@=0/signin_count@=0/live_stat@
=0/npv@=0/best_dlev@=0/cur_lev@=0/

天蓬老师天蓬老师2809 天前1245

全部回复(4)我来回复

  • 阿神

    阿神2017-04-17 14:37:57

    你这个结构体的大小,并不是你发送数据的长度。具体原因请参考结构体对齐相关内容。

    1

    2

    3

    4

    5

    6

    7

    8

    <code class="c">struct postData{

        int data_len;//4字节

        int data_len_2;//4字节

        short message = 689;//2字节

        char secreat = 0;//1字节

        char presv = 0;//1字节

        char body[31] = "type@=loginreq/roomid@=846805/";

    };</code>

    上面结构体的sizeof结果可能是4+4+2+1+1 + 32 = 44。最后的body会对齐到32字节。

    我用下面的代码测试了一下,连接不上。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    <code class="c">#include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <stdint.h>

    #include <sys/types.h>

    #include <sys/socket.h>

    #include <netinet/in.h>

    #include <arpa/inet.h>

    #include <unistd.h>

    #include <errno.h>

     

    struct postData{

        int32_t data_len;        //4字节

        int32_t data_len_2;        //4字节

        int16_t message;        //2字节

        int8_t secreat;            //1字节

        int8_t presv;            //1字节

        char body[0];   // = "type@=loginreq/roomid@=846805/";

    };

     

     

    int main()

    {

        int fd;

        struct sockaddr_in addr;

     

        if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1){

            perror("socket");

            return -1;

        }

     

        memset(&addr,0,sizeof addr);

        addr.sin_family = AF_INET;

        addr.sin_addr.s_addr = inet_addr("123.150.206.162");

        addr.sin_port = htons(8601);

     

        if(connect(fd,(struct sockaddr*)&addr,sizeof addr) == -1){

            perror("connect"); // 连接出错,输出  connect: Connection refused

            return -2;

        }

     

        struct postData* pdata = (struct postData*)malloc(64);

        strcpy(pdata->body,"type@=loginreq/roomid@=846805/");

        pdata->data_len = pdata->data_len_2 = sizeof(*pdata) + strlen(pdata->body) +1;

        printf("pdata->data_len = %d\n",pdata->data_len);

        pdata->message = 689;

        pdata->secreat = pdata->presv = 0;

         

        if(send(fd,pdata,pdata->data_len,0) != pdata->data_len){

            puts("send 未完成");

            return -3;

        }

     

        char buf[1024];

        if(recv(fd,buf,sizeof(buf),0) == -1){

            perror("recv");

            return -4;

        }

        printf("接收到数据:%s\n",buf);

         

        close(fd);

        return 0;

    }</code>

    回复
    0
  • ringa_lee

    ringa_lee2017-04-17 14:37:57

    早上又试了下,因为斗鱼它说除了登入请求还有其他的一些心跳检测,入组请求之类的,我都发送一遍后倒是有回应

    type@=error/code@=51/.

    应该是我结构体的构造有问题吧,C语言很多小东西不扎实,不是Socket的问题~

    回复
    0
  • 迷茫

    迷茫2017-04-17 14:37:57

    首先,body体官方不是说了有个'0'吗?所以你发的消息的这个body数组至少也得32吧。从性能以及内部内存对齐来考虑的话,不要吝惜这一点点存储空间,用 N * PAGE_SIZE的数组大小更好一点吧。

    回复
    0
  • PHPz

    PHPz2017-04-17 14:37:57

    请问你是在看的什么书学的,怎么用到斗鱼了?

    回复
    0
  • 取消回复