利用WinSocket發資料(一)
阿新 • • 發佈:2019-01-31
幫朋友寫的一個利用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; }