Tcp篇套接字编程学习笔记(三)

 
1、使用异步Socket
    当使用Connect与远程计算机进行连接的时候。如果对方计算机无法连接时,connect函数会等待75秒。这段时间很长,实际中我肯定不想让一个connect函数去等待那么长的时间。同样,再使用send,recv函数的时候,当发送缓冲区满或接受缓冲区满时函数也会阻塞。看看异步socket的特点,可以解决这个connect问题。可以设置socket的特点解决send,recv的超时等待问题。代码如下:
              SOCKET                           Sock;                                                             
              int                        iPort       = 0;
              TCHAR               lszIP[16] = {_T('/0')};
              char                     szRet[8] = {0};
              WSADATA          wsaData;
              CString               sPort = _T("");
 
              //GetDlgItem(IDC_EDIT1)->GetWindowTextW(lszIP,sizeof(lszIP));
              //GetDlgItem(IDC_EDIT2)->GetWindowTextW(sPort);
              //iPort = _wtoi(sPort.GetBuffer());
 
              //版本协商
              int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
 
              // 判断iResult 结果
 
              // 创建Socket
              Sock = socket ( AF_INET , SOCK_STREAM , 0 );
              if ( Sock < 0 ) {
                            return ;
              }
 
              try {
                            struct sockaddr_in serveraddr;
                            serveraddr.sin_family = AF_INET;
                            serveraddr.sin_port   = htons(short(iPort));
                            serveraddr.sin_addr.S_un.S_addr = inet_addr((const char *)UnicodeToAnsi(lszIP,NULL));
 
                            //set Recv and Send time out
                            int TimeOut=6000;           //设置发送超时6秒
                            if (::setsockopt(Sock,SOL_SOCKET,SO_SNDTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
                                          return ;
                            }
                            TimeOut=6000;   //设置接收超时6秒
                            if (::setsockopt(Sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
                                          return ;
                            }
 
                            //设置非阻塞方式连接
                            unsigned long ul = 1;
                            int ret = ioctlsocket(Sock, FIONBIO, (unsigned long*)&ul);
                            if (ret == SOCKET_ERROR)
                                          return ;
 
                            // 设置非阻塞方式后connect会立即返回,使用select来判断时候连接成功
                            connect ( Sock , (struct sockaddr*)&serveraddr , sizeof(serveraddr) );
                            struct timeval timeout ;
                            fd_set r;
 
                            FD_ZERO(&r);
                            FD_SET(Sock, &r);
                            timeout.tv_sec = 2; //连接超时2秒
                            timeout.tv_usec =0;
                            ret = select(0, 0, &r, 0, &timeout);
                            if ( ret <= 0 )
                            {
                                          ::closesocket(Sock);
                                          return ;
                            }
 
                            //一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
                            unsigned long ul1= 0 ;
                            ret = ioctlsocket(Sock, FIONBIO, (unsigned long*)&ul1);
                            if(ret==SOCKET_ERROR){
                                          ::closesocket (Sock);
                                          return ;
                            }
 
                            // 发送信息给服务器程序
                            {
                                          if ( 1 == send(Sock,"F",1,0) ) {
                                                        if ( 1 == recv(Sock,szRet,1,0) ) {
                                                                      closesocket(Sock);
                                                                      return ;
                                                        }
                                                        else {
                                                                      closesocket(Sock);
                                                                      return ;
                                                        }
                                          }
                            }
              }
              catch ( ... ){
                            TCHAR szError[DEF_TEMP_BUF]={0};
                            gszGetLastErrorText(szError, DEF_TEMP_BUF);
              }
              return ;
2、使用指定端口与服务器进行连接
   再第二篇中的 setWinSock函数中,我没有指定用哪个端口来连接。如果我在firewall上面设置了,只开放一部分端口,那我怎么用这部分端口来与远程计算机进行通讯?代码如下:
struct sockaddr_in stlocalSsin;
stlocalSsin.sin_family = AF_INET;
stlocalSsin.sin_port    = htons(short(9999));
stlocalSsin.sin_addr.S_un.S_addr = inet_addr((const char *)UnicodeToAnsi(lszIP,NULL));
 
// 设置本地Socket信息
if ( bind(Sock,(struct sockaddr*)&stlocalSsin,sizeof(stlocalSsin)) < 0) {
              return ;
}
// connect
   这样可以看到使用了9999号端口与远程计算机进行连接。
3、判断端口占用情况
   察看本地侦听端口可以使用bind函数看看是否成功。也可以使用connect看看是否能够连接上。那netstat命令是怎样获得端口使用信息的呢?用了个反编译工具在netstat中找到了很多函数。最后找到一个GetTcpTable函数: The GetTcpTable function retrieves the TCP connection table。同样可是使用GetUdpTable获得相关信息。代码如下:
// Declare and initialize variables
PMIB_TCPTABLE pTcpTable;
 
pTcpTable = (MIB_TCPTABLE*) malloc(sizeof(MIB_TCPTABLE));
DWORD dwSize = 0;
 
// Make an initial call to GetTcpTable to
// get the necessary size into the dwSize variable
if (GetTcpTable(pTcpTable, &dwSize, TRUE) == ERROR_INSUFFICIENT_BUFFER) {
 GlobalFree(pTcpTable);
 pTcpTable = (MIB_TCPTABLE*) malloc ((UINT) dwSize);
}
 
// Make a second call to GetTcpTable to get
// the actual data we require
if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) == NO_ERROR) {
 for (int i = 0; i < (int) pTcpTable->dwNumEntries; i++) {
    printf("State: %ld/n", pTcpTable->table[i].dwState);
 }
}
 
else {
 printf("/tCall to GetTcpTable failed./n");
                  
 LPVOID lpMsgBuf;
                 
 if (FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    dwRetVal,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL ))
 {
    printf("/tError: %s", lpMsgBuf);
 }
 LocalFree( lpMsgBuf );
}
 
 
 
使用完这个函数后可以看 dwState来确定状态。例如:
MIB_TCP_STATE_CLOSED     == closed
MIB_TCP_STATE_LISTEN     == Listening
MIB_TCP_STATE_SYN_SENT  == SYN Sent
MIB_TCP_STATE_SYN_RCVD  == SYN Received
MIB_TCP_STATE_ESTAB      == Established
MIB_TCP_STATE_FIN_WAIT1 == Waiting for FIN
MIB_TCP_STATE_FIN_WAIT2 == Waiting for FIN
MIB_TCP_STATE_CLOSE_WAIT         == Waiting for Close
MIB_TCP_STATE_CLOSING    == Closing
MIB_TCP_STATE_LAST_ACK  == Last ACK
MIB_TCP_STATE_TIME_WAIT == Time Wait
MIB_TCP_STATE_DELETE_TCB         == TCB deleted
 
 
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值