Visual C++ TCP网络编程学习

                      Visual C++网络编程学习


套接字地址结构体:

  struct sockaddr_in{
     short  sin_family; //指定地址格式,用AF_INET表示TCP/IP协议
     unsigned short sin_port; //端口号码
     struct in_addr  sin_addr; //IP地址
     char  sin_zero[8]; //统一结构体大小,预留下来的
  }

  地址设置:
  sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(80);
  addr.sin_addr.S_un.S_addr = inet_addr("168.192.1.10");

                  异步套接字 和 同步套接字
异步套接字 使socketAPI函数处于非阻塞模式, 通过消息机制,处理响应。
    主要的消息有: FD_ACCEPT (客户端连接消息)
                  FD_READ (读取发送来的消息)
                  FD_CLOSE (客户端或服务器关闭消息)
                  FD_CONNECT (connect函数在异步情况下,不会直接返回连接成功,会将连接结果通过消息FD_CONNECT发送)

同步套接字 会使socketAOI函数处于阻塞模式,直到有函数有响应是才返回。往往使用多线程进行操作。

异步套接字处理主要流程:
  创建好SOCKET后,调用:
::WSAAsyncSelect(mServerSock, m_hWnd, MY_SOCKET, FD_ACCEPT|FD_READ|FD_CLOSE)
  定义消息:#define  MY_SOCKET (WM_USER + 105)
  在响应对话框类中添加处理函数:
  在BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间加入:
  ON_MESSAGE(MY_SOCKET, &CTCPServerDlg::OnMySock)
处理函数:
LRESULT CTCPServerDlg::OnMySock(WPARAM wParam, LPARAM lParam)
{
    CString str;
    char cs[100] = {0};
    int row = mListCtrl.GetItemCount();    
    int iEvent = WSAGETSELECTEVENT(lParam); //消息类别
        int iEventErr = WSAGETSELECTERROR(lParam); //错误代码
    int len;
    len=sizeof(SOCKADDR);
    SOCKET CurSock= (SOCKET)wParam;
    sockaddr_in connectAddr;
    
    switch(iEvent) {
    case FD_ACCEPT:
        mAccpetSocksMap[iConnectNumber] = accept(CurSock, (sockaddr*)&connectAddr,&len);
        mListCtrl.InsertItem(row,inet_ntoa(connectAddr.sin_addr));    
        str.Format("%d", ntohs(connectAddr.sin_port) );
        mListCtrl.SetItemText(row, 1, str);
        str.Format("%s-%d连接上,已有%d位客户端连接!\r\n",inet_ntoa(connectAddr.sin_addr),
            ntohs(connectAddr.sin_port), iConnectNumber+1);
        iConnectNumber++;
        TRACE("连接了%d个客户端", iConnectNumber);
        mListBox.InsertString(listCount++, str);
        mListBox.SetCurSel(listCount - 1);
        break;
    case FD_READ:
        recv(CurSock, cs, 100, 0);
        sockaddr_in addr;
        ::getpeername(CurSock, (SOCKADDR*)&addr, &len);
        str = inet_ntoa(addr.sin_addr);
        str.AppendFormat("端口%d说:%s",ntohs(addr.sin_port),cs);
        mListBox.InsertString(listCount++, str);
        mListBox.SetCurSel(listCount - 1);
        send(CurSock, "OK", 3, 0);
        break;
    case FD_CLOSE:
        break;
    case FD_CONNECT:
        if(iEventErr == 0) {
            KillTimer(7);
            //AfxMessageBox("服务器连接成功");
            mTCPStatusStatic.SetWindowText("电子标签服务器已连接");
            mStationByTCP.isConnect = true;
        } else {
            //AfxMessageBox("服务器连接失败");
            mTCPStatusStatic.SetWindowText("连接失败,正在重新连接");
        }
        break;
    }
    return TRUE;
}

注意事项:

   1、在调用accept(CurSock, (sockaddr*)&connectAddr,&len)和getpeername(CurSock, (SOCKADDR*)&addr, &len)时,其第三个参数的应该用int len = sizeof(SOCKADDR)的引用,不能直接用(int *)sizeof(SOCKADDR)。
   2、在异步上,判断客户端是否连接上服务器,应该用消息,在消息函数中处理FD_CONNECT情况,不能直接用connect函数返回值,其返回值为SOCKET_ERROR时,也可能连接成功。
   3、异步情况上,在服务器端一般要处理FD_ACCEPT、FD_READ、FD_CLOSE消息。 而客户端一般处理FD_READ、FD_CLOSE、FD_CONNECT消息。
   4、消息处理函数的两个参数分别可转换为:
           WPARAM wParam; ---》SOCKET CurSock= (SOCKET)wParam;
           LPARAM lParam;----》int iEvent = WSAGETSELECTEVENT(lParam);//消息类别 (包含FD_ACCEPT、FD_READ、FD_CLOSE、FD_CONNECT等)
           LPARAM lParam;----》int iEventErr = WSAGETSELECTERROR(lParam); //错误代码(iEventErr ==0 表示成功)

   
    

服务器流程:

   1、初始化WINSOCK---->WSAStartup(WINSOCK_VERSION, &wsaData);
   2、初始化SOCKET ----->mServerSock = socket(AF_INET, SOCK_STREAM, 0);
   3、设置sockaddr_in(IP和Port) 如:
        localAddr.sin_family = AF_INET;
    localAddr.sin_port = htons(10100);
    localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   4、将SOCKET和sockaddr_in绑定-->bind(mServerSock, (sockaddr*)&localAddr, sizeof(localAddr));
   5、设置异步SOCKET--->::WSAAsyncSelect(mServerSock, m_hWnd, MY_SOCKET, FD_ACCEPT|FD_READ|FD_CLOSE)
   6、开启监听--->::listen(mServerSock, MaxConnectNumber);
   7、注册MY_SOCKET消息和其处理函数,如:
        7-1、在.h文件中加入:#define  MY_SOCKET (WM_USER + 101)
        7-2、在类声明中加入:afx_msg LRESULT OnMySock(WPARAM wParam, LPARAM lParam);
        7-3、在.cpp类实现中添加消息绑定注册宏:ON_MESSAGE(MY_SOCKET, OnMySock)//添加在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间
   8、实现函数OnMySock。
   9、添加发送函数---》send(mConnectSock, sendStr, 100, 0);
   10、关闭服务器---》 closesocket(mServerSock);
   11、关闭WINSOCK服务---》WSACleanup();
 
 

客户端流程:

   1、初始化WINSOCK---->WSAStartup(WINSOCK_VERSION, &wsaData);
   2、初始化SOCKET ----->mServerSock = socket(AF_INET, SOCK_STREAM, 0);
   3、设置异步SOCKET--->::WSAAsyncSelect(mServerSock, m_hWnd, MY_SOCKET, FD_ACCEPT|FD_READ|FD_CLOSE)
   4、设置远程服务器地址sockaddr_in remoteAddr;
        remoteAddr.sin_family = AF_INET;
    remoteAddr.sin_port = htons(Port);
    remoteAddr.sin_addr.S_un.S_addr = inet_addr(ip);
   5、注册MY_SOCKET消息和其处理函数,如:
        5-1、在.h文件中加入:#define  MY_SOCKET (WM_USER + 101)
        5-2、在类声明中加入:afx_msg LRESULT OnMySock(WPARAM wParam, LPARAM lParam);
        5-3、在.cpp类实现中添加消息绑定注册宏:ON_MESSAGE(MY_SOCKET, OnMySock)//添加在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间
   6、实现函数OnMySock。//特别注意处理FD_CONNECT消息,判断连接是否成功
   7、连接服务器---》::connect(mSock, (sockaddr*)&remoteAddr, sizeof(sockaddr));
   8、添加发送函数---》send(mConnectSock, sendStr, 100, 0);
   9、关闭服务器---》 closesocket(mServerSock);
   10、关闭WINSOCK服务---》WSACleanup();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值