TCP流式套接字的阻塞模式编程

在Windows环境下,套接口的通信方式分为两种:阻塞方式和非阻塞方式。阻塞方式下工作的套接口在进行I/O操作时,函数要等待到相关操作完成以后才能返回(或者可以使用WSACancelBlockingCall( )调用唤起一个阻塞操作)。 阻塞方式的套接口编程简单,易于实现。正因为如此,一个套接口的默认操作模式被设置为阻塞方式。

以下为测试阻塞模式TCP流式套接字编程,一个服务器两个客户端
服务器端程序:

#include < WinSock2.h>
#pragma comment ( lib, "ws2_32" )
#include < stdio.h>
int main()
{
    printf( "服务器端程序/n" );
    //---------------①加载-------------------------
    WSADATA wsaData;
    WORD wVersionRequested= MAKEWORD( 2 ,2 );
    if ( WSAStartup( wVersionRequested,& wsaData)!= 0 )
    {
        printf( "WSAStartup() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "①加载成功/n" );
    //----------------②创建流式套接字--------------
    SOCKET s= socket( AF_INET, SOCK_STREAM, 0 );
    if ( s== INVALID_SOCKET)
    {
        printf( "socket() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "②已创建监听套接口:【%d】/n" , s);
    //-----------------③绑定本地地址------------------
    struct sockaddr_in Sadd;
    Sadd.sin_family= AF_INET;
    Sadd.sin_port= htons( 1111 );
    Sadd.sin_addr.s_addr= inet_addr( "192.168.31.1" );
    if ( bind( s,( sockaddr*)& Sadd, sizeof ( Sadd))== SOCKET_ERROR)
    {
        printf( "bind() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "③绑定成功,本地IP地址:【%s】,端口号:【%d】/n" , inet_ntoa( Sadd.sin_addr), ntohs( Sadd.sin_port));
    //------------------④进入监听状态--------------------
    if ( listen( s, 5 )== SOCKET_ERROR)
    {
        printf( "listen() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "④进入监听状态/n" );
    //------------------⑤循环接受客户的连接请求-----------------
    printf( "⑤等待客户连接请求/n/n" );
    struct sockaddr_in Cadd;
    int CaddLen= sizeof ( Cadd);
    while ( TRUE )
    {
        SOCKET c= accept( s,( sockaddr*)& Cadd,& CaddLen);
        if ( c== INVALID_SOCKET)
        {
            printf( "accept() Failed,Error=【%d】/n" , WSAGetLastError());
            return 1 ;
        }
        else //**************开始发送、接收********************
        {
            printf( "客户已来,已创建用于本次连接的套接字是:【%d】/n" , c);
            printf( "客户端IP地址:【%s】,端口号:【%d】/n" , inet_ntoa( Cadd.sin_addr), ntohs( Cadd.sin_port));
            while ( 1 )
            {
                //-------接受-----
                char Rbuf[ 256 ];
                memset( Rbuf, 0 ,sizeof ( Rbuf));
                int SRecv= recv( c, Rbuf, 256 ,0 );
                if ( SRecv== SOCKET_ERROR)
                {
                    printf( "recv() Failed,Error=【%d】或客户端非法关闭连接/n" , WSAGetLastError());
                    break ;
                }
                else if ( SRecv== 0 )
                {
                    printf( "没接收到任何来自客户端的数据,或者客户端已关闭本次连接!!/n" );
                    break ;
                }
                else //------正确接收---
                {
                    printf( "接收到数据:【%s】/n" , Rbuf);
                    char Sbuf[]= "Hello! I am a server" ;
                    int isend= send( c, Sbuf, sizeof ( Sbuf), 0 );
                    if ( isend== SOCKET_ERROR)
                    {
                        printf( "send() Failed,Error=【%d】/n" , WSAGetLastError());
                        break ;
                    }
                    else if ( isend== 0 )
                    {
                        printf( "消息发送失败/n" );
                        closesocket( c);
                        break ;
                    }
                    else
                        printf( "给客户信息【%s】已发送/n" , Sbuf);
                } //end 正确接收
            } //end while2
        } //end 开始接收
        closesocket( c);
        printf( "关闭本次用于连接的套接字【%d】,和【%s】连接完毕/n/n" , c, inet_ntoa( Cadd.sin_addr));
    } //end while 1
    //---------------⑥关闭、释放--------------------
    closesocket( s);
    WSACleanup();
    return 0 ;
}

1号客户端程序:

#include < WinSock2.h>
#pragma comment( lib, "ws2_32" )
#include < stdio.h>
int main()
{
    printf( "1号客户端程序/n" );
    //-----------①加载----------------
    WSADATA wsaData;
    WORD wVersionRequested= MAKEWORD( 2 ,2 );
    if ( WSAStartup( wVersionRequested,& wsaData)!= 0 )
    {
        printf( "WSAStartup Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "①加载成功/n" );
    //-------------②创建流式套接字-----------------
    SOCKET c1= socket( AF_INET, SOCK_STREAM, 0 );
    if ( c1== INVALID_SOCKET)
    {
        printf( "socket() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "②已创建连接套接字:【%d】/n" , c1);
    //-------------绑定地址---------------------
    struct sockaddr_in C1add;
    C1add.sin_family= AF_INET;
    C1add.sin_port= htons( 2222 );
    C1add.sin_addr.s_addr= inet_addr( "192.168.31.2" );
    if ( bind( c1,( sockaddr*)& C1add, sizeof ( C1add))== SOCKET_ERROR)
    {
        printf( "bind() Failed,Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else
        printf( "绑定成功,本地IP地址:【%s】,端口号:【%d】/n" , inet_ntoa( C1add.sin_addr), ntohs( C1add.sin_port));
    //------------③连接请求---------------
    struct sockaddr_in Sadd;
    Sadd.sin_family= AF_INET;
    Sadd.sin_port= htons( 1111 );
    Sadd.sin_addr.s_addr= inet_addr( "192.168.31.1" );
    if ( connect( c1,( sockaddr*)& Sadd, sizeof ( Sadd))==- 1 )
    {
        printf( "Failed connect(),Error=【%d】/n" , WSAGetLastError());
        return 1 ;
    }
    else //*********连接成功,可以开始发送、接收************
    {
        printf( "③连接成功,服务器IP地址:【%s】,端口号:【%d】/n" , inet_ntoa( Sadd.sin_addr), ntohs( Sadd.sin_port));
        int a;
        printf( "希望发送数据吗?(键入“1”发送,键入其他值则退出)" );
        scanf( "%d" ,& a);
        while ( a== 1 )
        {
            //---发送-----
            char S_buf[]= "Hello!I am a client 1" ;
            int isend= send( c1, S_buf, strlen( S_buf), 0 );
            if ( isend== SOCKET_ERROR)
            {
                printf( "Failed send(),Error=【%d】,或者服务器意外关闭/n" , WSAGetLastError());
                return 1 ;
            }
            else if ( isend!= 0 )
                printf( "信息【%s】已发送/n" , S_buf);
            else
                printf( "信息无法发送给客户端/n" );
            //---接收----
            char R_buf[ 256 ];
            int RRecv;
            memset( R_buf, 0 ,sizeof ( R_buf));
            RRecv= recv( c1, R_buf, 256 ,0 );
            if ( RRecv== SOCKET_ERROR)
            {
                printf( "Failed recv(),Error=【%d】/n" , WSAGetLastError());
                return 1 ;
            }
            else if ( RRecv== 0 )
                printf( "无法收到来自服务器的任何数据,或者服务器意外关闭/n" );
            else
            {
                printf( "接收到来自服务器的数据:【%s】/n" , R_buf);
                printf( "希望继续发送数据吗?(键入”1“继续发送,键入其他值则退出)" );
                scanf( "%d" ,& a);
                if ( a!= 1 )
                    break ;
            }
        } //-------end 结束
        printf( "已选择退出连接/n" );
    } //------end 结束
    //-------------------④关闭、释放------------
    closesocket( c1);
    WSACleanup();
    printf( "④与服务器连接完毕/n" );
    return 0 ;
}

2号客户端程序与1号的相差无几,主要是提示文字变成“2号客户端”,绑定的IP地址也不一样。
先启动服务器端,再启动1号客户端,接着启动2号客户端,就会看到如图所示:

服务器端只有当1号客户端退出,才能收到2号客户端的通信。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值