Maison > Questions et réponses > le corps du texte
根据斗鱼给的开发者手册,用struct构建出应用层协议头,发送登入请求,建立连接成功但没有从服务器传回有效消息。
代码不长,边学socket边写的注释。
抓包显示成功的建立了连接,图片放在最后。
#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;
}
协议组成 众所周知,受 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/
阿神2017-04-17 14:37:57
你这个结构体的大小,并不是你发送数据的长度。具体原因请参考结构体对齐相关内容。
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/";
};
上面结构体的sizeof结果可能是4+4+2+1+1 + 32
= 44
。最后的body
会对齐到32
字节。
我用下面的代码测试了一下,连接不上。
#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;
}
ringa_lee2017-04-17 14:37:57
早上又试了下,因为斗鱼它说除了登入请求还有其他的一些心跳检测,入组请求之类的,我都发送一遍后倒是有回应
type@=error/code@=51/.
应该是我结构体的构造有问题吧,C语言很多小东西不扎实,不是Socket的问题~
迷茫2017-04-17 14:37:57
首先,body体官方不是说了有个'0'吗?所以你发的消息的这个body数组至少也得32吧。从性能以及内部内存对齐来考虑的话,不要吝惜这一点点存储空间,用 N * PAGE_SIZE的数组大小更好一点吧。