• 13034阅读
  • 2回复

【原创】教你写socket(一个项目例子的socket部分) [复制链接]

上一主题 下一主题
离线lxmhuendan
 

只看楼主 倒序阅读 楼主  发表于: 2005-08-18
我刚学过socket,自学的.看了一个例子.想和还不会的同志分享一下,如果你是高手那就算了.
我想这个对想用socket 的同志会有帮助的!
如果你认为我说的不好请指点,但不要仍砖头!~我QQ 57016584 谢谢!想要源代码的Q我

注: 1表示自己写的.2表示提供的-不用自己写的.
void CListenDlg::OnButton1()
{
    // TODO: Add your control notification handler code here
    CWinThread *pThread=NULL;                       CButton* pBtn=(CButton *)GetDlgItem(IDC_BUTTON1);     //2
    int n=pBtn->GetCheck();     //2                  
    m_HostIp=GetIp();           //1 得到本机IP        
    if(1==n)     //开始监听
    {
        if(CreateSock()!=0)     //1 - 建立createsock成=0
        {    
              AfxMessageBox("WinSock设置失败");        
              DestroyWindow();     //2 销毁windows    
        }
        else
        {
              b_IsRun=TRUE;
              pThread=AfxBeginThread(RecvIpPro,this); //2 启动线程
        }
        pBtn->SetWindowText("停止监听");     //2
    }
    else //停止监听
    {
        b_IsRun=FALSE;
        if(pThread)               //pthread=null    
        {
              TerminateThread(pThread->m_hThread, 0);                                                             //2 该函数用来结束由hThread
                                                      //参数指定的线程,并把0设成该线程的退出码
                                          CloseHandle(pThread->m_hThread);     //2
        }
        if(m_RawSock)
              closesocket(m_RawSock);
        pBtn->SetWindowText("开始监听");
    }
}
//得到本机IP
char* GetIp()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    char name[255];
    char *ip;
    PHOSTENT hostinfo;
    wVersionRequested = MAKEWORD( 2, 0 );
    if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )//wsastartup成功返回0
    {
       
        if( gethostname ( name, sizeof(name)) == 0) //2 获得本机的名字
        {
              if((hostinfo = gethostbyname(name)) != NULL)//2 得到IP地址
              {
              ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
    //2 将参数in所指的网络二进制的数字转换成网络地址,然/后将指向此网络
    // 地址字符串的指针返回。 返回值. 成功则返回字符串指针,失败则返回NULL。
              }
        }
       
        WSACleanup( );
    }
    return ip;
}
//建立原始套接字
int CListenDlg::CreateSock()
{
    int err;
    char name[10];                  
    hostent *pHostent;
    int port=8310;                   //端口号,自定义5001,8080 ……
    SOCKADDR_IN sockaddr;
    m_RawSock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);     //2 互联网,流操作,0
    if(m_RawSock==INVALID_SOCKET)                       //若socket没有创建成
    {    
        return WSAGetLastError();                       //2 socket创建失败
    }
    err=gethostname(name,10);     //2 获得本机的名字
    if(err==SOCKET_ERROR)        
    {
        return WSAGetLastError();                       //2 取本机用户名失败
    }
    pHostent=gethostbyname (name);                     //获得你的机器的IP 地址

    sockaddr.sin_family=AF_INET;
    sockaddr.sin_port=htons(port);
    memcpy(&sockaddr.sin_addr.s_addr,pHostent->h_addr_list[0],
        pHostent->h_length);                             //ip 地址
   
    err=bind(m_RawSock,(SOCKADDR *)&sockaddr,sizeof(sockaddr));//绑定(将端口,ip和socket)
    if(err==SOCKET_ERROR)
    {
        return WSAGetLastError(); //取本机用户名,失败未绑定
    }
    BOOL bOptval=TRUE;

    //设置套节字选项
    setsockopt(m_RawSock,SOL_SOCKET,SO_REUSEADDR,(char*)&bOptval,sizeof(bOptval));//2 置套接口选项
    err=setsockopt(m_RawSock,IPPROTO_IP,IP_HDRINCL,(char*)&bOptval, //IP_HDRINCL该选项使之能操作IP头
        sizeof(bOptval));
    if(err==SOCKET_ERROR)
    {
        return WSAGetLastError(); //设置套节字选项失败
    }

    //把网卡置于混杂模式。获取IO操作的相关信息
    DWORD dwBufferLen[10] ;
    DWORD dwBufferInLen = 1 ;
    DWORD dwBytesReturned = 0 ;
    err=WSAIoctl (                             //2
        m_RawSock,           //一个指定的套接字                        
        SIO_RCVALL,     //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包 ,控制操作码                
        &dwBufferInLen,           //指向输入数据流的指针                      
        sizeof(dwBufferInLen),     //输入数据流的大小(字节数)                        
        &dwBufferLen,             //指向输出数据流的指针            
        sizeof(dwBufferLen),       //输出数据流的大小(字节数                  
        &dwBytesReturned,         //指向输出字节流数目的实数值          
        NULL,                 //指向一个WSAOVERLAPPED结构
        NULL                               //指向操作完成时执行的例程
        );//最后两参数设置非阻塞
    if(err==SOCKET_ERROR)
    {
        return WSAGetLastError();   //2 设置失败
    }
    return 0;
}
//在线程chi中不断接受IP包
UINT RecvIpPro(LPVOID lpParam)
{
    int err=0;
    int recvLen;
    CListenDlg* pDlg=(CListenDlg*)lpParam;
    char recvBuf[MAX_PACK_LEN]={0};//接受的最大的报文
    while(b_IsRun)
    {
        recvLen=recv(pDlg->m_RawSock,recvBuf,MAX_PACK_LEN,0);//接受数据
       
        if(err==SOCKET_ERROR)
        {
              if(WSAGetLastError()==WSAEWOULDBLOCK) //如果错误为阻塞那么将继续接受
                  continue;
              break;
        }
        //处理已经接受到的IP包
        EnterCriticalSection(&pDlg->m_ls);
        pDlg->SplitIpPack(recvBuf,recvLen); //分解IP包
        pDlg->ShowIpInfo(recvBuf,recvLen); //显示数据
        LeaveCriticalSection(&pDlg->m_ls);
    }
    return 0;
}
//分解IP包
void CListenDlg::SplitIpPack(char *pData, int len)
{
    IP_HEADER* pIpHead;
    pIpHead=(IP_HEADER*)pData; //转为IP头结构
    SOCKADDR_IN saSource,saDest; //中间变量分别为源IP地址结构和目标IP地址结构

    //得到包中协议
    int iProtocol;
    iProtocol=pIpHead->proto;
    //得到协议字符形式表示m_szProtocol
    strncpy(m_szProtocol,CheckProtocol(iProtocol),MAX_PROTO_TEXT_LEN);


    //得到源IP
    saSource.sin_addr.s_addr=pIpHead->sourceIP;
    strncpy(m_szSourceIP,inet_ntoa(saSource.sin_addr),MAX_ADDR_LEN);

    //得到目标IP
    saDest.sin_addr.s_addr=pIpHead->destIP;
    strncpy(m_szDestIP,inet_ntoa(saDest.sin_addr),MAX_ADDR_LEN);

    //得到TTL
    int ttl;
    ttl=pIpHead->ttl;
    wsprintf(m_szTTL,"%d",ttl);

    //得到头长度
    int ihLen=sizeof(unsigned long)*(pIpHead->h_lenver & 0xf);

    m_ihLen=ihLen;
    unsigned short srcPort=0,destPort=0;
    switch(iProtocol) {
    case IPPROTO_TCP:
        TCP_HEADER* pTcpHead;
        pTcpHead=(TCP_HEADER*)(pData+ihLen);
        srcPort=ntohs(pTcpHead->th_sport);
        destPort=ntohs(pTcpHead->th_dport);
        wsprintf(m_szSourcePort,"%d",srcPort);
        wsprintf(m_szDestPort,"%d",destPort);
        break;
                            }
}
//将协议int转为字符串
char* CListenDlg::CheckProtocol(int iProtocol)
{
    for(int i=0; i<MAX_PROTO_NUM; i++)
    {
        if(ProtoMap.ProtoNum==iProtocol)
        {
              return ProtoMap.ProtoText;
        }
    }
        return "";
}
[ 此贴被XChinux在2005-08-22 21:05重新编辑 ]
快慢机
离线huishouliu
只看该作者 1楼 发表于: 2009-04-07
楼主你有病吗?MFC程序发到QT论坛来?
MSN/Email :huishouliu@126.com
离线ccdeath
只看该作者 2楼 发表于: 2010-04-10
狗日的。够真有病。我草楼主™。
快速回复
限100 字节
 
上一个 下一个