帮朋友写的一个利用winsocket发数据的两段代码.本指望可以通过socket来走低层一些的数据交互,没想到还是被封杀。没想到竟然直接检测socket.就没用这种思路往下做下去了;
不过这个过程中也对Winsocket有了一定了解;发出来给有需要的朋友;
计划是利用socket 走tcp协议,然后传输一个特定文件到服务器段,然后服务器段接受这个文件,整个过程有CRC32校验数据完整性,代码在内网测试是ok,的,外围一开始就被杀掉了。fuck.
其他不多说了。代码有详细解释。
发送端程序:
#include "stdafx.h" #include <winsock2.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #pragma comment(lib,"ws2_32.lib") //必须引入的静态库 windows 系统会自带; #define DEFAULT_PORT 5019 // 端口 #define SEND_BUFFER_LENTH 1024 //发送的buffer数据长度不包括crc32和length #define REVE_BUFFER_LENTH 100 //服务端反馈过来的大小 int main(int argc, char **argv){ int again=1; int msg_len=0;//发送实际len int msg_reve_len = 0; //接受实际 //int addr_len; struct sockaddr_in server_addr; struct hostent *hp; SOCKET connect_sock; WSADATA wsaData; //文件流 fstream walletFile; //发送buffer //长距离发送必须要做crc16验证 最后4byte 长度 和放crc16值 4byte char sendBuffer[SEND_BUFFER_LENTH+8]={0}; char recvBuffer[REVE_BUFFER_LENTH]={0}; // 服务器名称 这个后续可以写上服务器的名字 //也可以直接指定IP char *server_name = "localhost"; unsigned short port = DEFAULT_PORT; unsigned int addr; //打开一个文件 目标 二进制打开 walletFile.open("c:\\test.txt",ios::binary|ios::in|ios::out); //先赋初值,清0 memset(sendBuffer,0,SEND_BUFFER_LENTH+8); memset(recvBuffer,0,REVE_BUFFER_LENTH); if(!walletFile.good())//文件不正常打开 { //关闭文件 walletFile.close(); return 0; } //也可以由程序运行时带入参数, //后续考虑那种自由的大一点; /*if (argc != 3){ printf("echoscln [server name] [port number]\n"); return -1; } else{ server_name = argv[1]; port = atoi(argv[2]); }*/ //初始化套接字库 //失败暂时关掉, //后续可以考虑下多次try catch if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR){ return -1; } //得到服务器 IP信息 //通过服务器名称来获得 hp = gethostbyname(server_name); //server_name如果是这种形式:“192.168.1.1” //要先把这种字符串转一下 //addr = inet_addr(server_name); //hp = gethostbyaddr((char*)&addr, 4, AF_INET); //地址没有解析出来,要退出, //后续可以考虑下多次try catch if (hp==NULL) { WSACleanup(); return -1; } //赋初值 0 memset(&server_addr, 0, sizeof(server_addr)); //拷贝解析后的ip memcpy(&(server_addr.sin_addr), hp->h_addr, hp->h_length); //默认参数 server_addr.sin_family = hp->h_addrtype; //端口 server_addr.sin_port = htons(port); //定义使用TCP套接字连接 connect_sock = socket(AF_INET,SOCK_STREAM, 0); // if (connect_sock == INVALID_SOCKET){ WSACleanup(); return -1; } //连接成功 if (connect(connect_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){ WSACleanup(); return -1; } //循环收发数据开始 //实际读取出的大小 unsigned int realRead = 0; unsigned int crcValue = 0; do{ //一次读取1024byte //赋初值 memset(sendBuffer,0,SEND_BUFFER_LENTH+8); walletFile.read(sendBuffer,SEND_BUFFER_LENTH); //要做数据crc运算 并附加到数据buffer后面 //这里做运算的length必须是实际的大小,否则出错 //这样的话就要把每次发送的长度也封装咦,因为服务端要做CRC32校验要长度啊。 realRead= walletFile.gcount();//取得实际读取的大小; //貌似没必要 //sendBuffer[realRead]='\0';//手动添加结束符 crcValue= crc32(sendBuffer,realRead); memcpy(&sendBuffer[SEND_BUFFER_LENTH],&realRead,4);//长度写入 memcpy(&sendBuffer[SEND_BUFFER_LENTH+4],&crcValue,4); //crc32值 //} //else{ // //没有读到或者读完了 // break; //} //发数据 发整个带有crc16的数据 前面1024是数据,后面两个byte是crc16值 //service 那边要先检测crc16的值,不对的话要重发送; msg_len = send(connect_sock, sendBuffer,SEND_BUFFER_LENTH+8, 0); //msg_len为实际发送的长度 if (msg_len == SOCKET_ERROR){ WSACleanup(); again=0; return -1; } //发完了 if (msg_len == 0){ closesocket(connect_sock); WSACleanup(); again=0; return -1; } //从服务器收返回的数据 msg_reve_len = recv(connect_sock, recvBuffer,REVE_BUFFER_LENTH, 0); if(REVE_BUFFER_LENTH==msg_reve_len){ //crc32值 int crcValue = 0; int dataLen = 0; char receiveCrc32[4]={0}; char realen[4] = {0}; for(int ti =0;ti<4;ti++) //取crc32 { receiveCrc32[ti]=recvBuffer[REVE_BUFFER_LENTH-4+ti]; } memcpy(&crcValue,receiveCrc32,4); for(int tk =0;tk<4;tk++) //取长度 { realen[tk]=recvBuffer[REVE_BUFFER_LENTH-8+tk]; } memcpy(&dataLen,realen,4); int dataCrc32 = crc32(recvBuffer,dataLen); //fuck 这里咋整啊,客服端发数据过去有丢失,服务端发过来也有丢失,也要重发,这不死循环? //待解决的问题啊 //如果服务端传回来的数据完好, if(dataCrc32==crcValue) { //如果是resend if(recDataCheck(recvBuffer,6,1)) { int timesi = 0; //重发这个数据包 do{ msg_len = send(connect_sock, sendBuffer,SEND_BUFFER_LENTH+8, 0); //收服务端反馈数据 timesi++; }while(msg_len==0&×i<3); } //如果是sendnext if(recDataCheck(recvBuffer,8,1)) { //直接下一个读取和发送 continue; } } } else if (msg_reve_len == SOCKET_ERROR){ //异常 closesocket(connect_sock); WSACleanup(); again=0; return -1; } else if (msg_len == 0){ //服务端发了0 closesocket(connect_sock); WSACleanup(); again=0; return -1; } }while(again==1&&!walletFile.eof()); //扫尾工作 //关闭文件 walletFile.close(); closesocket(connect_sock); WSACleanup(); } unsigned int crc32(char* InStr,unsigned int len){ //生成Crc32的查询表 unsigned int Crc32Table[256]; int i,j; unsigned int Crc; for (i = 0; i < 256; i++) { Crc = i; for (j = 0; j < 8; j++) { if (Crc & 1) Crc = (Crc >> 1) ^ 0xEDB88320; else Crc >>= 1; } Crc32Table[i] = Crc; } //开始计算CRC32校验值 Crc=0xffffffff; for(int i=0; i<len; i++){ Crc = (Crc >> 8)^ Crc32Table[(Crc & 0xFF) ^ InStr[i]]; } Crc ^= 0xFFFFFFFF; return Crc; } //接受结果检测 //1 为 重发检测 其他为 是否ok检测 bool recDataCheck(char * receiveData,int receiveLength,int _type) { if(1==_type) return needResend(receiveData,receiveLength); else return sendOk(receiveData,receiveLength); } //检测是否是重发浮标 bool needResend(char * receiveData,int receiveLength) { char* reSend ="resend"; try{ for(int i = 0;i<receiveLength;i++) { if(reSend[i]!=receiveData[i]) return false; } } catch(...) { return false; } return true; } //检测服务短 收过来的是不是已接收ok bool sendOk(char * receiveData,int receiveLength) { char* sendOk ="sendnext"; try{ for(int i = 0;i<receiveLength;i++) { if(sendOk[i]!=receiveData[i]) return false; } } catch(...) { return false; } return true; }