开发网络安全程序基础
// MyTcpTran.cpp: implementation of the CMyTcpTran class.
//
//////////////////////////////////////////////////////////////////////
#include "MyTcpTran.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMyTcpTran::CMyTcpTran()
{
//默认INVALID_SOCKET 嵌套字无效
m_Socket = INVALID_SOCKET;
}
CMyTcpTran::~CMyTcpTran()
{
}
BOOL CMyTcpTran::InitSocketLibray(int lowver,int higver )
{
WORD wVersion =0 ;
int errret = -1;
WSADATA wsaData;
//MAKEWORD 将两个BYTE类型合并为WORD型
//高位字节指明副版本
//低位字节指明主板本
//如果使用2.1版本的SOCKET,则代码如下 wVersion=MAKEWORD(2,1)
wVersion = MAKEWORD(lowver,higver);
//加载和初始化SOCKET对应的动态链接库WS2_32.DLL的一些信息,为使用SOCKET做准备
errret = WSAStartup(wVersion,&wsaData);
if( LOBYTE( wsaData.wVersion) !=2 ||
HIBYTE( wsaData.wVersion) !=2 )
{
MessageBox(NULL,"winsocket库版本低","提示",MB_OK);
return FALSE;
}
return TRUE;
}
SOCKET CMyTcpTran::InitSocket( int SocketType, string strBindIp,u_short BindPort,int opt)
{
//创建一个用于网络通信的套接字
SOCKET socketid = INVALID_SOCKET;
socketid = socket(PF_INET,SOCK_STREAM,0);
SOCKADDR_IN sockStruct;
//AF_INET使用TCP/IP协议
sockStruct.sin_family = AF_INET;
if( strBindIp.empty() )
{
//strBindIp为空,则INADDR_ANY SOCKET能够接受任何IP的信息
sockStruct.sin_addr.S_un.S_addr = INADDR_ANY;
}else
{
//strBindIp不为空,则strBindIp char *后 转换为无符号长整型
sockStruct.sin_addr.S_un.S_addr = inet_addr(strBindIp.c_str());
}
//将BindPort转换为网络字节后保存
sockStruct.sin_port = htons(BindPort);
//不绑定端口
if( SocketType == SOCKETNOBIND )
{
//与所指定的计算机进行连接
if(connect(socketid,(LPSOCKADDR)&sockStruct,sizeof(sockStruct)) == SOCKET_ERROR)
{
//OutputDebugString("连接错误!");
//关闭已经打开的套接字 防止占用内存
closesocket(socketid);
shutdown(socketid,2);
//设置套接字无效
socketid = INVALID_SOCKET;
}
m_Socket = socketid;
}
//如果是绑定本地端口
else if( SocketType == SOCKETBIND )
{
//绑定由sockStruct指定的网络计算机IP和端口
if(bind(socketid,(sockaddr*)&sockStruct,sizeof(sockaddr_in)) == SOCKET_ERROR)
{
closesocket(socketid);
socketid = INVALID_SOCKET;
}
else
{
//绑定IP和端口成功,窃听来自网络其他计算机的连接队列
if( listen(socketid,SOMAXCONN) == SOCKET_ERROR )
{
closesocket(socketid);
socketid = INVALID_SOCKET;
}
}
m_Socket = socketid;
}
return socketid;
}
SOCKET CMyTcpTran::myaccept(SOCKET s,struct sockaddr* addr,int* addrlen)
{
//创建新的套接字并初始化为INVALID_SOCKET
SOCKET accpsocket = INVALID_SOCKET;
//accept 调用成功返回可用的套接字,失败返回INVALID_SOCKET
accpsocket = accept(s,addr,addrlen);
return accpsocket;
}
int CMyTcpTran::myrecv(SOCKET sock, char *buf, int len, int flag , int overtime ,char*EndMark,BOOL soonflag)
{
//定义变量
int ret;
int nLeft = len;
int idx = 0;
int nCount = 0;
//fd_set 文件描述符集合
fd_set readfds;
struct timeval timeout;
//设置超时时间
timeout.tv_sec = 0;
timeout.tv_usec = 500;
//返回从操作系统启动到现在经过的毫秒数
DWORD s_time = GetTickCount();
while ( nLeft > 0 )
{
//接收消息
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;
//如果接收到的信息为退出信息
if(msg.message == WM_QUIT)
return 0;
//将SET清零
FD_ZERO( &readfds );
//将FD放入SET
FD_SET( sock , &readfds );
if( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR )
{
return SOCKET_ERROR;
}
DWORD e_time = GetTickCount( );
if ( !FD_ISSET( sock , &readfds ) )
{
if( e_time - s_time > overtime*1000 ) //超时
return SOCKET_TIMEOUT;
else
continue;
}
ret = recv( sock, &buf[idx], nLeft, flag );//接收数据
if( soonflag == TRUE )
{
//立即返回接收到的字节数
return ret;
}
s_time = e_time ; // 只要有数据就重新置初始时间值
if ( ret <= 0 )
{
//错误处理
int LastError = GetLastError();
if ( ( -1 == ret ) && ( WSAETIMEDOUT == LastError ) )
continue;
if ( ( -1 == ret ) && ( WSAEWOULDBLOCK == LastError ) )
{
if ( nCount < 2000 )
{
Sleep( 10 );
nCount++;
continue;
}
}
return ret;
}
nCount = 0;
nLeft -= ret;
idx += ret;
if( EndMark != NULL && idx>5)
{
if( strstr(buf+(idx-5),EndMark) != NULL )
{
break;
}
}
}
return idx;
}
int CMyTcpTran::mysend(SOCKET sock, const char *buf, int len, int flag,int overtime)
{
//定义变量
int ret;
int nLeft = len;
int idx = 0;
fd_set readfds;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 500;
DWORD s_time = GetTickCount();
while ( nLeft > 0 )
{
//向对话框发送关闭消息
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;
if(msg.message == WM_QUIT)
return 0;
FD_ZERO( &readfds );
FD_SET( sock , &readfds );
int errorret = select( 0 , NULL, &readfds, NULL , &timeout );
if( errorret == SOCKET_ERROR )
{
OutputDebugString("mysendEx SOCKET 错误");
return SOCKET_ERROR;
}
//计算当前时间
DWORD e_time = GetTickCount( );
if ( !FD_ISSET( sock , &readfds ) )
{
//如果超时,返回
if( e_time - s_time > overtime*1000 )
{
OutputDebugString("mysendEx发送数据超时");
return 0;
}
else
{
//OutputDebugString("发送数据FD_ISSET 超时");
continue;
}
}
ret = send( sock, &buf[idx], nLeft, flag );
if ( ret <= 0 )
{
return ret;
}
nLeft -= ret;
idx += ret;
}
return len;
}
// MyTcpTran.h: interface for the CMyTcpTran class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MYTCPTRAN_H__98D1E493_C9EA_4E23_AB2C_0BA8907888EB__INCLUDED_)
#define AFX_MYTCPTRAN_H__98D1E493_C9EA_4E23_AB2C_0BA8907888EB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define SOCKETBIND 1
#define SOCKETNOBIND 2
#define SOCKET_TIMEOUT -100
#include "winsock2.h"
#include <string.h>
#include <iostream>
using namespace std;
#pragma comment (lib,"ws2_32.lib")
class CMyTcpTran
{
public:
CMyTcpTran();
virtual ~CMyTcpTran();
public:
static BOOL InitSocketLibray(int lowver,int higver);
public:
SOCKET InitSocket( int SocketType, string strBindIp,u_short BindPort,int opt);
SOCKET myaccept(SOCKET s,struct sockaddr* addr,int* addrlen);
int mysend(SOCKET sock, const char *buf, int len, int flag,int overtime);
int myrecv(SOCKET sock, char *buf, int len, int flag , int overtime,char*EndMark,BOOL soonflag=FALSE);
private:
SOCKET m_Socket;
};
#endif // !defined(AFX_MYTCPTRAN_H__98D1E493_C9EA_4E23_AB2C_0BA8907888EB__INCLUDED_)