利用WinSocket发数据(一)

帮朋友写的一个利用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;

}


你可能感兴趣的:(数据,socket,二进制,tcp,服务器)