Windows网络编程 2 【转】

Windows网络编程使用winsock。Winsock是一个基于Socket模型的API,在Windows系统中广泛使用。
使用Winsock进行网络编程需要包含头文件Winsock2.h,需要使用库ws2_32.lib,包含方法:可以使用语句来告诉编译器连接该库
#pragma comment(lib, “ws2_32.lib”);
如果使用VS,可以通过“项目” --> “XX属性”--> “连接器”-->“输入”--> “附加依赖项”添加ws2_32.lib。 (XX为当前工程名)

面向连接的C/S程序工程流程图

使用Winsock API编制的网络应用程序中,在调用任何一个Winsock函数之前都必须检查协议栈安装情况,使用函数WSAStartup()完成操作。
● 一个服务端的例子

void server::startServer()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested=MAKEWORD(2,2);
    if(WSAStartup(wVersionRequested,&wsaData)!=0)
    {
        //Winsock初始化错误
        msgBox.exec();
        return;
    }
    if(wsaData.wVersion!=wVersionRequested)
    {
        //Winsock版本不匹配
        WSACleanup();
        return;
    }

    if ((m_sk = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
    {
        WSACleanup();
        return;
    }
    bool ok;
    unsigned short port = ui.portLineEdit->text().toInt(&ok, 10);
    if (ok == false)
    {
        //端口输入错误
        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();
        return;
    }

    sockaddr_in addr;
    addr.sin_family = AF_INET; //使用互联网际协议,即IP协议
    addr.sin_port = htons(port);
    addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    if (bind(m_sk, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
    {
        //绑定端口失败

        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();
        return;
    }

    if (listen(m_sk, 10) == SOCKET_ERROR)
    {
        //监听端口失败
        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();
        return;
    }
    updateMsgRecs(tr("等待连接..."));
    //创建线程去等待连接
    HANDLE h = CreateThread(NULL, 0, &server::acceptProc, (LPVOID)this, 0, 0);
    if (h == NULL)
    {
        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();
        return;
    }
    CloseHandle(h);
}

● 监听线程函数

DWORD WINAPI server::acceptProc(LPVOID lpParamter)
{
    /*server *p_server = (server *)lpParamter;
    sockaddr_in client_addr;
    int len = sizeof(client_addr);
    char msgBuff[256];
    int sk;
    while (1)
    {
        if ((sk = ::accept(p_server->sk(), (sockaddr*)&client_addr, &len) )== SOCKET_ERROR)
        {
            emit p_server->haveNewMsg(QObject::tr("accept 出错"));
            break;
        }

        sprintf(msgBuff, "新连接来自%s", inet_ntoa(client_addr.sin_addr));
        emit p_server->haveNewMsg(msgBuff);
        emit p_server->newClient(inet_ntoa(client_addr.sin_addr), sk);
    }*/

    server *p_server = (server *)lpParamter;
    int client[FD_SETSIZE];
    fd_set allset, rset;
    sockaddr_in client_addr;
    int len;
    int clientfd;
    int sockfd;

    int i;
    for (i=0; i<FD_SETSIZE; i++)
        client[i] = -1;
    FD_ZERO(&allset);
    int listenfd = p_server->sk();
    FD_SET(listenfd, &allset);

    int nready;
    int maxfd = listenfd;
    int maxi = -1;
    char buff[MAX_LEN+1];

    while (1)
    {
        rset = allset;
        nready = select(maxfd+1, &rset, NULL, NULL, NULL);
        if (FD_ISSET(listenfd, &rset)) //new connection
        {
            len = sizeof(client_addr);
            if ( (clientfd = ::accept(p_server->sk(), (sockaddr*)&client_addr, &len)) == SOCKET_ERROR)
            {
                emit p_server->haveNewMsg(QObject::tr("accept 出错"));
                break;
            }
            //找出client数组中第一个为-1的单元存放已经连接的socket
            for (i=0; i<FD_SETSIZE; i++)
            {
                if (client[i] <0)
                {
                    client[i] = clientfd;
                    break;
                }
            }
            if (i == FD_SETSIZE)
            {
                emit p_server->haveNewMsg(QObject::tr("error: too many clients!"));
                break;
            }
            //sprintf(buff, "新连接来自%s", inet_ntoa(client_addr.sin_addr));
            //emit p_server->haveNewMsg(buff);
            emit p_server->newClient(inet_ntoa(client_addr.sin_addr), clientfd);
            FD_SET(clientfd, &allset);
            if (clientfd > maxfd)
                maxfd = clientfd;
            if (i>maxi)
                maxi = i;
            if (--nready <= 0)
                continue;
        }
        for (i=0; i<=maxi; i++)
        {
            if ( (sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset))
            {
                int n;
                //客户端已经关闭连接
                if ( (n = recv(sockfd, buff, MAX_LEN, 0 )) <= 0)
                {
                    closesocket(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                    emit p_server->haveNewMsg(QObject::tr("client closed"));
                    emit p_server->sClientClose(sockfd);
                }
                else //收到数据
                {
                    buff[n] = 0;
                    emit p_server->haveNewMsg( buff, sockfd);
                    if (--nready <= 0)
                        break;
                }
            }
        } //for (i=0; i<=maxi; i++)
    }
    return 0;
}

  一个客户端的例子

void client::connectServer()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested=MAKEWORD(2,2);
    if(WSAStartup(wVersionRequested,&wsaData)!=0)
    {
        //Winsock初始化错误
        QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("Winsock初始化错误"), QMessageBox::Ok, 0);
        msgBox.exec();
        return;
    }
    if(wsaData.wVersion!=wVersionRequested)
    {
        //Winsock版本不匹配
        QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("Winsock版本不匹配"), QMessageBox::Ok, 0);
        msgBox.exec();
        WSACleanup();
        return;
    }

    if ((m_sk = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
    {
        QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("创建socket失败"), QMessageBox::Ok, 0);
        msgBox.exec();
        WSACleanup();
        return;
    }

    sockaddr_in addr;
    addr.sin_family = AF_INET;

    bool ok;
    unsigned short port = ui.portLineEdit->text().toInt(&ok, 10);
    if (ok == false)
    {
        QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("端口输入错误"), QMessageBox::Ok, 0);
        msgBox.exec();
        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();
        return;
    }
    addr.sin_port  = htons(port);
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    if (0 == ::connect(m_sk, (sockaddr *)&addr, sizeof(addr)))
    {
        updateMsgRecs(tr("连接成功..."));
        HANDLE h = CreateThread(NULL, 0, &client::recvProc, (LPVOID)this, 0, 0);
        CloseHandle(h);
    }
    else
    {
        QMessageBox msgBox(QMessageBox::Warning, tr("错误"), tr("连接出错"), QMessageBox::Ok, 0);
        msgBox.exec();
        closesocket(m_sk);
        m_sk = -1;
        WSACleanup();

    }
}

●  winsock APIs

网络连接函数
socket 创建套接字
bind 绑定本机端口
connect 建立连接
listen 监听端口
accept 接受连接
recv, recvfrom 数据接收
send, sendto 数据发送
close, shutdown 关闭套接字
转换函数
inet_addr() 点分十进制数表示的IP地址转换为网络字节序的IP地址
inet_ntoa() 网络字节序的IP地址转换为点分十进制数表示的IP地址
字节顺序转换函数
htonl 4字节主机字节序转换为网络字节序
ntohl  4字节网络字节序转换为主机字节序
htons 2字节主机字节序转换为网络字节序
ntohs 2字节网络字节序转换为主机字节序
网络信息检索函数
gethostname 获得主机名
getpeername 获得与套接口相连的远程协议地址
getsockname 获得套接口本地协议地址
gethostbyname 根据主机名取得主机信息
gethostbyaddr 根据主机地址取得主机信息
getprotobyname 根据协议名取得主机协议信息
getprotobynumber 根据协议号取得主机协议信息
getservbyname 根据服务名取得相关服务信息
getservbyport 根据端口号取得相关服务信息
getsockopt/setsockopt 获取/设置一个套接口选项
ioctlsocket 设置套接口的工作方式

时间: 2024-10-03 09:11:53

Windows网络编程 2 【转】的相关文章

Windows网络编程经验小结

转自:CSDN网友的强贴,其ID:gdy119 (夜风微凉) 1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket: BOOL bReuseaddr=TRUE; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL)); 2. 如果要已经处于连接状态的soket

Windows网络编程

第一章 序言 我写这个专题的目的,一方面是为了通过对网络编程再一次系统的总结,提高自己的网络编程水平,特别是Windows下的网络编程水平.同一时候,我也希望,能为众多初学网络编程的人提供一点帮助,由于我開始学习网络编程的时候,能找到的资料就非常少.当然,花钱能够买到翻译版本号的书:) 首先向大家推荐一本非常好的參考书,Network Programming for Microsoft Windows 2nd, 初学网络编程的时候我还不知道有这样一本好书,仅仅是上各大论坛把能找到的网络编程方面的

windows网络编程的一些理论

参考自<VC++深入详解> 这是我在看书时记录下来的东西. 注:下面的Socket其实都应该是socket 第14章网络编程 Socket是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建,通过绑定与驱动程序建立关系. 此后,应用程序给Socket的数据,由Socket交给驱动程序向网络上发送出去. 计算机从网络上收到与该Socket绑定的IP地址和端口号相关的数据后,由驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据. 14.1 计算机网络基本知识. 1

72&gt;&gt;Windows 网络编程

1 网络编程 API 2 3 4 int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); lpWSAData 是一个返回值:成功返回 0,失败返回 -1,错误代码 WSASYSNOTREADY 表示基础网络子系统没有准备好网络通行,WSAVERNOTSUPPORTED 表示 Socket 版本不支持,WSAEINPROGRESS 表示一个阻塞的 Sockets 操作在进程中,WSAEPROCLIM 表示 Sockets 支持的

windows 网络编程[转]

利用winsock编写网络应用程序服务端的步骤简述如下WSAStartup 初始化网络编程库 socket 创建套接字 bind 指定地址.端口,绑定套接字 listen 进入监听状态 accept 等待接收新连接 send/recv 收发数据 closesocket 关键套接字 WSAStartup 释放对动态库的使用 下面详细介绍各API 1. Winsock初始化 调用int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData

Windows 网络编程(2)--重叠I/0模型

5).重叠I/O模式(overlapped) 常用函素: 1.WSASocket : 创建套接字 2.TCP WSASend WSARecv 3.UDP: WSASendTo WSARecvFrom 4.AccepEx (Mswsock.lib库导出) WSAIoctl 5.数据类型 WSAOVERLAPPED (wsaoverlapped) 函数: WSAGetOverlappedResult 使用: 缓冲区对象 typedef struct _BUFFER_OBJ { OVERLAPPED

windows网络编程中文 笔记(二)

IPv4 地址段 IPv4地址类别 种类 网络部分 第1个数字 端点数字 A  8位  0-127  16777216 B  16位  128-191  65526 C  24位  193-223  256 D  N/A  224~239  N/A E   N/A  240~255   N/A 1. A类地址(1)A类地址第1字节为网络地址,其它3个字节为主机地址.(2)A类地址范围:1.0.0.1-126.255.255.254(3)A类地址中的私有地址和保留地址:① 10.X.X.X是私有地

Windows网络编程--选择(select)模型

选择模型是I/O模型中最简单的一个.Server端通过创建两个套接字集合fdOld和fdNew,在循环中通过事件添加和移除未决IO套接字句柄.测试的时候先启动服务端再启动客户端. 以下为Server端源代码(在VS2010下测试通过): #include "stdafx.h"#include<WinSock2.h>#include<Windows.h> #include<iostream> #pragma comment(lib,"ws2_

windows网络编程入门

windows Sockets 的版本: 头文件:WINSOCK.h 库文件:wsock32.lib 动态困:WINSOCK.DLL 头文件:WINSOCK2.h 库文件:WS2_32.lib 动态困:WS2_32.DLL 服务端: WSADATA wsd; //WSADATA变量 SOCKET sServer; //服务器套接字 SOCKET sClient; //客户端套接字 SOCKADDR_IN addrServ;; //服务器地址 char buf[ BUF_SIZE]; //接收数据