您的位置:首页 > 理论基础 > 计算机网络

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

2013-06-30 19:41 645 查看
在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号客户端的通信。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: