• socket编程入门(函数)


    Windows Socket 编程

       

    一、 Windows sockets开发概述

    网络开发可被理解为:基于互联网,利用网络开发技术,开发能运行在网络上的软件,如网络游戏、聊天软件等。

    Windows sockets是一套在Microsoft Windows环境下的网络编程接口,它包含一组库函数,使开发人员可以利用Windows消息驱动机制进行网络应用程序开发

    Windows sockets 主要有 Windows sockets 1.1(1.0)和Windows sockets 2.2(2.0) 两个版本。

    版本

    头文件

    库文件

    动态库

    1.1

    WINSOCK.h

    wsock32.lib

    WINSOCK.DLL

    2.2

    WINSOCK2.h

    WS2_32.lib

    WS2_32.dll

    Socket1.1版本中用到的库函数主要有:

    Accept(), bind(), closesocket(), connect(), getpeername(), getsockname(), htonl(), htons(), inet_addr(), inet_ntoa(), listen(), ntohl(), ntohs(), recv(), recvfrom(), select(), send(), sendto(), shutdown(), socket()等

    Socket1.1版本中对Windows扩展的函数主要有:

    WSAStartup(), WSACleanup(), WSAGetLastError(), WSAIsBlockint()等

    Socket2.0版本中对Windows扩展的函数主要有:

    WSAACCEPT(), WSACONNECT(), WSAHTONL(), WSAHTONS(), WSANTOHL(), WSANTOHS(), WSARECV(), WSARECVFROM(), WSASEND(), WSASENDTO(), WSASOCKET()等

       

       

    二、TCP/IP 简介

    & TCP/IP协议

    TCP/IP协议是网络通信中最常用的协议

    OSI标准

    TCP/IP模型

    协议

    应用层

    应用层

    HTTP/FTP

    表示层

      

      

    会话层

      

      

    传输层

    传送层

    TCP/UDP

    网络层

    网络层

    IP/ARP(地址解析协议)

    数据链路层

    数据链路层

      

    物理层

      

      

    套接字:应用层到传送层的接口

    & 端口:

    0-1023:通用端口号

    1024-49151:应用程序使用

    49152-65535:动态、私有端口

       

       

       

    三、WINDOWS SOCKETS 基础

    (一)套接字

    套接字:网络应用程序借口,应用层与传送层得接口

       

    (二)TCP,UDP 连接过程

    Tcp

      

    Udp

    Server

    Client

      

    Server

    Client

    创建套接字

    创建套接字

      

    创建套接字

    创建套接字

    绑定

      

      

    绑定

    发送数据

    监听

    连接

      

    接受数据

      

    接受连接

      

      

    关闭

    关闭

    收发数据

    收发数据

      

      

      

    关闭

    关闭

      

      

      

    对应tcp、udp,至少有两种套接字可供编程使用,即流套接字和数据包套接字

    在Windows sockets中有一个新的数据类型SOCKET表示套接字,声明如下:

    Typedef unsigned int u_int;

    Typedef u_int SOCKET;

    即用一个特殊的整型变量表示套接字

    (三)sockets中用到的函数

    & 开始sockets编程

    利用vc 开发sockets程序时,需首先导入库文件,导入库文件的方法:

    1.头文件中添加代码:#pragma comment(lib,"wsock32.lib");或"WS2_32.lib"

    2.菜单栏"project"—"project settings"对话框---"link"选项卡---"category"下拉框中选择"input"----"object/library modules"文本框中添加"wsock32.lib"(前面加空格)

    推荐使用第一种方法,因第二种方法在每次打开工程时,都需从新执行添加步骤。

    Socket2版本兼容socket1版本,但如果程序中用到socket2版本中的函数时,需导入socket2的库文件。

       

    & WSAStartup()

    功能:对Winsock服务的初始化。应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。

    声明:WSAStartup(

    __in        WORD wVersionRequested,     //程序请求使用的Socket版本

    __out    LPWSADATA lpWSAData)    //操作系统返回支持的Socket的版本

    返回:成功时返回0

    wVersionRequested:准备加载的动态库版本,高字节指定副版本,低字节指定主版本

    LpWSAData:指针,WSADATA结构,返回被加载的动态库特征

    用到的其他知识:

    wVersionRequested对象可用MAKEWORD函数进行赋值e.g.MAKEWORD(2.0)

    wsaData返回后,可用LOBYTE(wsaData),HIBYTE(wsaData)查看返回的主版本号与副版本号

    例如:

    WORD wVersionRequest MAKEWORD(2,2);

    WSADATA wsaData;

    int errCode=WSAStartup(wVersionRequest, &wsaData); //初始化

    if(errCode != 0){......} //error

    if(LOBYTE(wsaData)!=2 || HIBYTE(wsaData)!=2){……}; //主、副版本号

       

    & socket()

    功能:创建套接字,利用socket1.1版本中的socket()函数或socket2.2版本中的WSASocket()函数可实现此功能

    声明:SOCKET socket(

    __in        Int af,                        //协议的地址家族

    __in        Int type,                        //协议的套接字类型

    __in        Int protocol)                    //协议

    af:地址家族,创建tcp或udp连接时,此参数为AF_INET(Address family地址家族)

    type:套接字类型,可选项有:

    SOCK_STREAM(流式套接字,tcp使用)

    SOCK_DGRAM(数据报套接字,udp使用)

    SOCK_RAM(原始套接字,直接处理ip协议)

    protocol:对于SOCK_STREAM,该字段为IPPROTO_TCP或0(自动匹配)

        对于SOCK_DGRAM,该字段为IPPROTO_UDP或0(自动匹配)

    返回:socket 类型,失败时返回INVALID_SOCKET

    用到的其他知识:

    Socket类型:

    定义:typedef unsigned int u_int;

    Typedef u_int SOCKET;

    Socket对象也就是一个特殊的整数

    取值范围:0到(INVALID_SOCKET - 1)

        创建时,若返回值为INVALID_SOCKET,则创建失败。

        #define INVALID_SOCKET (SOCKET)(~0)

    例如:

    SOCKET s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    If(INVALID_SOCKET == s) {……} //创建失败

       

    & bind()

    功能:套接字绑定到地址

    声明:int bind(

    __in        SOCKET s,                     //要绑定的套接字

    __in        const struct sockaddr FAR* name , //绑定到的地址

    __in        int namelen);                    //地址的长度

    返回:失败时为SOCKET_ERROR;

    例如:

    Struct sockaddr_in servAddr;

       

    servAddr.sin_family=AF_INET;

    servAddr.sin_port=htons(4999);

    servAddr.sin_addr.s_addr=htonl(INADDR_ANY);

    //servAddr.sin_addr.s_addr=inaddr_any

    //servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");

       

    int errorCode=bind(s, (SOCKET*)&servAddr, sizeof(servAddr)):

    if(SOCKET_ERROR==errorCode) {……} //error

       

       

    & listen()启动监听

    功能:将套接字设置为监听模式

    声明:int listen(

    __in        socket s,                    //要设置为监听的套接字

    __in        int backlog);                //等待队列最大长度

    返回:成功时返回0,失败时返回 SOCKET_ERROR

    例如:

    Int Val=listen(s, 5);

    If(SOCKET_ERROR==Val) {……} //error

       

    & accept()

    功能:接受一个连接请求

    声明:socket accept(

    __in        socket s,                     //监听套接字

    __out    struct sockaddr FAR* addr,    //地址

    __out    int FAR* addrlen)            //地址长度

    返回:代表客户端的socket ,失败时返回 INVALID_SOCKET;

    例如:

    SOCKET sAccept;

    Sockaddr_in addrClient;

    Int addrClientLen=sizeof(addrClient);

    sAccept=accept(s,(SOCKADDR*)&addrClient,&addrClientLen);

    if(INVALID_SOCKET==sAccept) {……} //error

       

    & recv() 或 WSARecv()

    功能:接收数据

    声明:int recv(

    __in        socket s,            //套接字

    __in        char FAR* buf,     //缓冲区

    __in        int len,             //缓冲区长度

    __in        int flags)            //标志,0:无特殊行为

    返回:成功时,返回接受的字节数,失败时,返回SOCKET_ERROR

    例如:

    Char buf[BUF_LEN];

    Int readLen;

    readLen=recv(sAccept,buf,BUF_LEN,0);

    if(SOCKET_ERROR==readLen) {……} //error

       

    & send() 或 WSASend()

    功能:发送数据

    声明:int send(

    __in        socket s,                //套接字

    __in        const char FAR* buf,    //缓冲区

    __in        int len ,                //缓冲区长度

    __in        int flags)                //标志,0:无特殊行为

    返回:失败时,SOCKET_ERROR

    例如:

    Char buf[BUF_LEN];

    Int writeLen;

    writeLen= send (sAccept,buf,BUF_LEN,0);

    if(SOCKET_ERROR==writeLen) {……} //error

       

    & Closesocket()

    功能:关闭套接字,释放资源

    声明:int closesocket(

    __in        s);            //要关闭的套接字

    返回:WSAENOTSOCK错误

       

    & Shutdown()

    功能:关闭套接字连接

    声明:int shutdown(

    __in        socket s,        //套接字

    __in        int how);        // SD_RECEIVE:不接受,SE_SEND:不发送,SD_BOTH:都不

    返回:int

       

    & connect()

    功能:连接到服务器

    声明:int connect(

    __in        socket s,                            //套接字

    __in        const struct sockaddr FAR* name ,        //服务器地址

    __in        int namelen)                        //服务器地址长度

    返回:失败时,返回SOCKET_ERROR

    例如:

    SOCKET sHost; //连接服务器的套接字

    SOCKEADDR_IN addrServerAddr;//服务器地址

       

    sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    addrServerAddr.sinfamily=AF_INET;

    addrServerAddr.sin_port=htons(serverPort);

    addrServerAddr.sin_addr.s_addr=htohl(serverIP);

       

    int Val= connect (sHost, (LPSOCKADDR)&addrServerAddr, sizeof(addrServerAddr));

    if(SOCKET_ERROR==Val) {……} //error

       

    & sendto()

    功能:发送数据

    定义:int sendto(

    SOCKET s,

    const char FAR* buf,

    int len,

    int flags,

    const struct sockaddr FAR* to,

    int tolen);

       

    & recvfrom()

    功能:接受数据,返回发送数据主机的地址

    声明:int recvfrom(

    __in        SOCKET s,                //接受套接字

    __in        char FAR* buf;                //接受缓冲区

    __in        len,                        //接受缓冲区大小

    __out    struct sockaddr FAR* from;    //返回发送主机地址

    __out    int FAR* fromlen)            //地址长度

    返回:成功时,返回接受数据的长度;失败时,返回SOCKET_ERROR

    例如:

    char buf[BUF_LEN];

    SOCKADDR_IN addrClient;

    Int nAddrClient=sizeof(addrClient);

    recvfrom(s,buf,BUF_SIZE,0,(SOCKADDR*)&c addrClient,& nAddrClient)

       

    & Socketaddr_in 结构

       

    Struct sockaddr

    Struct sockaddr_in

    {

    unsigned short sa_family;

    har sa_data[14]

    }

    { short sin_family;

    Unsigned short sin_port;

    Struct in_addr sin_addr;

    Unsigned char sin_zero[8];

    }

    Sa_family:地址家族,

    大多为AF_INET,

    表示ip协议簇

    Sa_data:协议地址

    Sin_family:地址家族,

    大多为AF_INET,表示ip协议簇

    Sin_port:端口号

    Sin_addr:存储ip地址

    Sin_zero:填充用

      

    在linux下

    在windows下

      

    Typedef struct in_addr

    { unsigned long s_addr;

    }

    Typedef struct in_addr

    {

    Union s_un{

    Struct { char s_b1, s_b2, s_b3, s_b4;} s_un_b;

    Struct { unsigned short s_w1,s_w2;}s_un_w;

    Unsigned long s_addr;

    }s_un

    }in_addr

      

    S_addr:存储的ip地址

      

     代码:

    /*

    *socket编程--tcp连接--服务器端

    */

    #include <iostream>

    using namespace std;

     

    #include <winsock2.h>

    #pragma comment(lib,"ws2_32.lib")

     

    #define DEFAULT_PORT 9090

     

    int main()

    {

    //==========初始化socket库环境===========

    WSADATA wsaData;

    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)

    {

    cout<<"WSAStartup failed"<<endl;

    return -1;

    }

     

    //===========创建套接字=================

    SOCKET sServer; //服务器套接字

    sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    if(INVALID_SOCKET==sServer)

    {

    cout<<"socket failed"<<endl;

    WSACleanup();

    return -1;

    }

     

    //===========绑定套接字=================

    SOCKADDR_IN addrServer;

    addrServer.sin_family=AF_INET;

    addrServer.sin_port=htons(DEFAULT_PORT);

    addrServer.sin_addr.s_addr=INADDR_ANY;

    //addrServer.sin_addr.s_addr=htonl(INADDR_ANY);

    //addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");

     

    int val=bind(sServer,(LPSOCKADDR)&addrServer,sizeof(SOCKADDR_IN));

    if(SOCKET_ERROR==val)

    {

    cout<<"bind failed"<<endl;

    closesocket(sServer);

    WSACleanup();

    return -1;

    }

     

    //===========监听=======================

    val=listen(sServer,SOMAXCONN);

    if(SOCKET_ERROR==val)

    {

    cout<<"listen failed"<<endl;

    closesocket(sServer);

    WSACleanup();

    return -1;

    }

     

    //===========接受客户端连接==============

    SOCKET sClient;

    sockaddr_in addrClient;

    int addrClientLen=sizeof(addrClient);

    sClient=accept(sServer,(sockaddr FAR*)&addrClient,&addrClientLen);

    if(INVALID_SOCKET==sClient)

    {

    cout<<"accept failed"<<endl;

    closesocket(sServer);

    WSACleanup();

    return -1;

    }

     

    //=========接收数据==========================

    char buf[1024];

    ZeroMemory(buf,1024);

    val=0;

    val=recv(sClient,buf,1024,0);

    if(SOCKET_ERROR==val)

    {

    cout<<"recv failed"<<endl;

    closesocket(sServer);

    closesocket(sClient);

    WSACleanup();

    return -1;

    }

    cout<<buf<<endl;

     

    //===========退出===========================

    closesocket(sServer);

    closesocket(sClient);

    WSACleanup();

     

    return 0;

    }

     

     

    /*

    *socket编程--tcp连接--客户端

    */

    #include <iostream>

    using namespace std;

     

    #include <winsock2.h>

    #pragma comment(lib,"ws2_32.lib")

     

    #define DEFAULT_PORT 9090

    #define BUF_SIZE 1024

    int main()

    {

     

    SOCKET sHost; //服务器套接字

    SOCKADDR_IN servAddr; //服务器地址

    char buf[BUF_SIZE]; //接受数据缓冲区

    int retVal;

     

    //=========创建套接字====================

    WSADATA wsd; //WSADATA变量

    if(WSAStartup(MAKEWORD(1,0),&wsd)!=0)

    {

    cout<<"WSAStartup failed!"<<endl;

    return -1;

    }

    if((int)LOBYTE(wsd.wVersion)!=1 || (int)HIBYTE(wsd.wVersion)!=0)

    {

    cout<<"version error!"<<endl;

    return -1;

    };

    cout<<"WSAStartup ok......"<<endl;

     

    //===========建立套接字=================

    sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    if(INVALID_SOCKET==sHost)

    {

    cout<<"socket failed!"<<endl;

    WSACleanup();

    return -1;

    }

    cout<<"socket ok......"<<endl;

     

    //=============连接服务器=================

    servAddr.sin_family =AF_INET;

    servAddr.sin_addr .s_addr=inet_addr("127.0.0.1");

    servAddr.sin_port =htons(DEFAULT_PORT);

     

    retVal=connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr));

    if(SOCKET_ERROR==retVal)

    {

    cout<<"connect failed!"<<endl;

    closesocket(sHost);

    WSACleanup();

    return -1;

    }

    cout<<"connect success!"<<endl;

     

    //==============发送数据===================

     

    ZeroMemory(buf,BUF_SIZE);

    strcat(buf,"hello");

     

    retVal=send(sHost,buf,strlen(buf),0);

    if(SOCKET_ERROR==retVal)

    {

    cout<<"send failed!"<<endl;

    closesocket(sHost);

    WSACleanup();

    return -1;

    }

    cout<<"send "<<retVal<<" bytes."<<endl;

    cout<<"they are:"<<buf<<endl;

     

    ZeroMemory(buf,BUF_SIZE);

     

    //=============接收数据==============

    retVal=recv(sHost,buf,BUF_SIZE,0);

    if(SOCKET_ERROR==retVal)

    {

    printf("recv failed!\n");

    closesocket(sHost);

    WSACleanup();

    return -1;

    }

    cout<<"recv access,recv "<<retVal<<" bytes,they are:"<<endl;

    cout<<buf<<endl;

     

     

     

    //--------退出

    shutdown(sHost,SD_BOTH);

    closesocket(sHost);

    WSACleanup();

    cout<<"closed"<<endl;

    return 0;

    }

  • 相关阅读:
    shell流程控制
    shell编程变量介绍与表达式详解
    shell编程简介
    反向代理与负载均衡
    存储库之mongodb,redis,mysql
    请求库之requests,selenium
    解析库之re、beautifulsoup、pyquery
    爬虫基本原理
    Django 函数和方法的区别
    Django 知识补漏单例模式
  • 原文地址:https://www.cnblogs.com/mutou3221/p/3063373.html
Copyright © 2020-2023  润新知