1
1.1代码示例
# include <stdio.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/ip.h>
# include <arpa/inet.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
int main ( void )
{
int sockfd= 0 ;
int ret= 0 ;
struct sockaddr_in seraddr;
char tmpbuff[ 4096 ] = { "I need some offers" } ;
int cnt= 0 ;
ssize_t nsize= 0 ;
sockfd= socket ( AF_INET, SOCK_STREAM, 0 ) ;
if ( - 1 == sockfd)
{
perror ( "fail to socket" ) ;
return - 1 ;
}
seraddr. sin_family= AF_INET;
seraddr. sin_port= htons ( 50000 ) ;
seraddr. sin_addr. s_addr= inet_addr ( "192.168.1.123" ) ;
ret= connect ( sockfd, ( struct sockaddr * ) & seraddr, sizeof ( seraddr) ) ;
if ( - 1 == ret)
{
perror ( "fail to connect" ) ;
return - 1 ;
}
while ( 1 )
{
# if 0
memset ( tmpbuff, 0 , sizeof ( tmpbuff) ) ;
sprintf ( tmpbuff, "client send:### %d" , cnt) ;
cnt++ ;
nsize= send ( sockfd, tmpbuff, strlen ( tmpbuff) , 0 ) ;
if ( - 1 == nsize)
{
perror ( "fail to send" ) ;
return - 1 ;
}
# endif
# if 1
memset ( tmpbuff, 0 , sizeof ( tmpbuff) ) ;
nsize= recv ( sockfd, tmpbuff, sizeof ( tmpbuff) , 0 ) ;
if ( - 1 == nsize)
{
perror ( "fail to recv" ) ;
return - 1 ;
}
# endif
printf ( "client recv:### %s\n" , tmpbuff) ;
}
close ( sockfd) ;
return 0 ;
}
int main ( void )
{
int sockfd= 0 ;
struct sockaddr_in seraddr;
int ret= 0 ;
int confd= 0 ;
char tmpbuff[ 4096 ] = { 0 } ;
ssize_t nsize= 0 ;
sockfd= socket ( AF_INET, SOCK_STREAM, 0 ) ;
if ( - 1 == sockfd)
{
perror ( "fail to socket" ) ;
return - 1 ;
}
seraddr. sin_family= AF_INET;
seraddr. sin_port= htons ( 50000 ) ;
seraddr. sin_addr. s_addr= inet_addr ( "192.168.1.123" ) ;
ret= bind ( sockfd, ( struct sockaddr * ) & seraddr, sizeof ( seraddr) ) ;
if ( - 1 == ret)
{
perror ( "fail to bind" ) ;
return - 1 ;
}
ret= listen ( sockfd, 10 ) ;
if ( - 1 == ret)
{
perror ( "fail to listen" ) ;
return - 1 ;
}
while ( 1 )
{
confd= accept ( sockfd, NULL , NULL ) ;
if ( - 1 == confd)
{
perror ( "fail to accept" ) ;
return - 1 ;
}
# if 0
memset ( tmpbuff, 0 , sizeof ( tmpbuff) ) ;
nsize= recv ( confd, tmpbuff, sizeof ( tmpbuff) , 0 ) ;
if ( - 1 == nsize)
{
perror ( "fail to recv" ) ;
return - 1 ;
}
else if ( 0 == nsize)
{
return 0 ;
}
# endif
memset ( tmpbuff, 0 , sizeof ( tmpbuff) ) ;
sprintf ( tmpbuff, "server send:### %s" , tmpbuff) ;
nsize= send ( confd, tmpbuff, strlen ( tmpbuff) , 0 ) ;
if ( - 1 == nsize)
{
perror ( "fail to send" ) ;
return - 1 ;
}
}
close ( confd) ;
close ( sockfd) ;
return 0 ;
}
1.2运行结果
(1)运行服务器
(2)运行客户端
现象如下:
客户端发生阻塞
(1)关闭服务器:
客户端不阻塞-说明recv函数为非阻塞状态
总结:
(1)如果将服务器accept函数放在while循环内部:同时运行客户端与服务器,可以发现服务器可以与多个客户端建立连接(解决的问题-服务器并发访问)。
(2)但是只能进行一次数据发送(虽然解决了服务器的并发访问问题,但是对于大量的数据传输却手足无措)
小意外:当服务器端退出,此时客户端不再阻塞,正常执行函数体。(这就说明了,此时recv函数为非阻塞状态=》那么服务器和客户端同时运行,为什么会发生阻塞?)
补充:
(1)如果将服务器端accept函数放在while循环外部(对比TCP文件传输):
1)只有一个客户端能够与服务器建立连接并进行数据收发;其它客户端被阻塞,无法与服务器建立连接。(问题:(1)服务器只能与一个客户端建立连接?(2)那么如何解决这个问题?(3)是从服务端解决这个问题,还是从客户端解决这个问题? 先解决问题(3):显然,要解决这个问题肯定是要从服务器端去解决--客户端是向服务器端发起连接请求,那么具体是否能够建立连接,显然是取决于服务器端的意愿和能力;所以,多个客户端向服务器端发起连接请求,能不能实现的关键在于服务器能不能接受多个客户端接入,服务器端是否允许多个客户端接入。 下面再解决问题(2):解决这个问题,其实用一句话来表述就是解决服务器并发访问问题,这个问题后面专项解决,现在只需要明白所面临的问题是服务器并发访问的问题即可。)
(2)如果将connect函数放在循环外部,将accept函数放在循环外部,此时意味着:客户端与服务器端第一次建立连接,可以发送一次数据;发完数据接着进行第二次,第三次。。。连接请求;此时当然是报错!因为同一个网络套接字只能建立一次连接,不能重复建立连接(这是由TCP通信机制决定的);但是这种方式可以将服务器同时与多个客户端建立连接。。。。。。。。。。。。。。总结一下就是:客户端与服务器端要进行多次请求连接-建立连接;那么每进行一次通信,都必须关闭(close)通信套接字(已经建立三次握手,四次挥手连接的套接字confd-accept)。
问题:
(1)在客户端或者服务器的