C++网络编程


900 浏览 5 years, 7 months

2.1 因特网服务器1

版权声明: 转载请注明出处 http://www.codingsoho.com/

实例1: 因特网服务器

SocketAPI就不做介绍了,这个不是本课程的重点

先实现一个简单的服务器,它监听数据,显示结果并退出。

包含文件
#ifdef WIN32                // windows 95 and above
    #include "winsock2.h"
    #include "Ws2tcpip.h"
#else                       // UNIX/Linux
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <arpa/inet.h>
#endif
// End Code Block 2.1 - Header Includes

根据判断预处理红WIN32是否定义,告知它是在WINDOW操作系统还是在Unix/Linux机器上运行。根据不同的操作系统,包含不同的头文件

平台兼容定义
// Code Block 2.2 - Redefinitions and globals For Cross-Compatibility
#ifdef WIN32                // windows 95 and above
    WSADATA g_wsadata;      // winsock data holder
    #define CloseSocket closesocket
    #define GetSocketError WSAGetLastError
    #define StartSocketLib WSAStartup( MAKEWORD( 2, 2 ), &g_wsadata );
    #define CloseSocketLib WSACleanup();
    #ifndef socklen_t
        typedef int socklen_t;
    #endif
#else                       // Unix/Linux
    #define CloseSocket close
    #define GetSocketError errno
    #define StartSocketLib {}
    #define CloseSocketLib {}
#endif
// End Code Block 2.2 - Redefinitions and globals For Cross-Compatibility

Socket API和Winsock library在某些方面有差异,所以需要统一调用接口,让他们在应用调用处没有相同。 上面的接口中,将函数名进行了统一,代码逻辑实现时可以用这个封装过的接口,而不需要特别关心是windows还是linux系统。

C++标准iostream库
#include <iostream>             // load the iostream library
using namespace std;            // use the std namespace
其他代码
#include <memory.h>
int main()
{
    int err;                    // for getting errors
    // start the socket library
    StartSocketLib;
    // BEGIN CODE BLOCK 2.3 - Create a Listening Socket on port 4000
    // create a socket
    int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    // check if socket was created
    if( sock == -1 )
    {
        cout << "Socket creation error!" << endl;
        return 0;
    }
    cout << "Socket created!" << endl;
    // create a sockaddr_in for binding, listening on port 4000
    struct sockaddr_in socketaddress;
    socklen_t sa_size = sizeof( struct sockaddr_in );
    socketaddress.sin_family = AF_INET;
    socketaddress.sin_port = htons( 4000 );
    socketaddress.sin_addr.s_addr = htonl( INADDR_ANY );
    memset( &(socketaddress.sin_zero), 0, 8 );
    // bind the socket
    err = bind( sock, (struct sockaddr*)&socketaddress, sa_size );
    if( err == -1 )
    {
        cout << "Socket binding error!" << endl;
        return 0;
    }
    cout << "Socket bound!" << endl;
    // listen on the socket
    err = listen( sock, 16 );
    if( err == -1 )
    {
        cout << "Socket listening error!" << endl;
        return 0;
    }
    cout << "Socket listening, waiting for connection..." << endl;
    // END CODE BLOCK 2.3 - Create a Listening Socket on port 4000
    // wait for an incomming connection now
    int datasock;
    datasock = accept( sock, (struct sockaddr*)&socketaddress, &sa_size );
    if( datasock == -1 )
    {
        cout << "Socket accepting error!" << endl;
        return 0;
    }
    cout << "Socket accepted, waiting for data..." << endl;
    // receive data
    char buffer[128];
    err = recv( datasock, buffer, 128, 0 );
    if( err == -1 )
    {
        cout << "Socket receiving error!" << endl;
        return 0;
    }
    cout << "Data received:" << endl;
    cout << buffer << endl;
    shutdown( datasock, 2 );
    CloseSocket( datasock );
    shutdown( sock, 2 );
    CloseSocket( sock );
    CloseSocketLib;
}

上面的代码中包括以下功能

  • 错误报告 int err;,每一步操作都可能出错,该变量用于纯粹错误值。
  • 创建套接字 - int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );,生成套接字sock
  • 绑定套接字 - bind( sock, (struct sockaddr*)&socketaddress, sa_size );
  • 监听套接字 - listen( sock, 16 );
  • 等待套接字 - datasock = accept( sock, (struct sockaddr*)&socketaddress, &sa_size );,当收到连接时,创建一个新的套接字datasock
  • 接收套接字 - recv( datasock, buffer, 128, 0 );
  • 关闭套接字 - 接收完成后,关闭套接字和停止系统 shutdown( datasock, 2 ); CloseSocket( datasock ); shutdown( sock, 2 ); CloseSocket( sock );

程序在编译时碰到错误 > undefined-reference-to-imp-wsacleanup
参考 https://stackoverflow.com/questions/18559028/undefined-reference-to-imp-wsacleanup 解决该问题

In DevC++, navigate to Project >> Project Options (or via usually ctrl+h); then in the "Parameters" tab there is a button "Add Library or Object" and then add libws2_32.a.

本例路径为 > "D:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib/libws2_32.a"