Linux的Socket IO模型趣解

2019-10-13 17:07:06于丽

前言 

之前有看到用很幽默的方式讲解Windows的socket IO模型,借用这个故事,讲解下linux的socket IO模型; 

老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系。
他们的信会被邮递员投递到他们小区门口的收发室里。这和Socket模型非常类似。 

下面就以老陈接收信件为例讲解linux的 Socket I/O模型。 

一、同步阻塞模型 

老陈的女儿第一次去外地工作,送走她之后,老陈非常的挂心她安全到达没有;
于是老陈什么也不干,一直在小区门口收发室里等着她女儿的报平安的信到; 

这就是linux的同步阻塞模式; 

在这个模式中,用户空间的应用程序执行一个系统调用,并阻塞,直到系统调用完成为止(数据传输完成或发生错误)。 

Socket设置为阻塞模式,当socket不能立即完成I/O操作时,进程或线程进入等待状态,直到操作完成。 

如图1所示:

 

/*
 * brief
 * tcp client
 */

#include 
#include 
#include 
#include 
#include 
#define SERVPORT 8080
#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
 int sockfd, recvbytes;
 char rcv_buf[MAXDATASIZE]; /*./client 127.0.0.1 hello */
 char snd_buf[MAXDATASIZE];
 struct hostent *host;  /* struct hostent
     * {
     * char *h_name; // general hostname
     * char **h_aliases; // hostname's alias
     * int h_addrtype; // AF_INET
     * int h_length; 
     * char **h_addr_list;
     * };
     */
 struct sockaddr_in server_addr;

 if (argc < 3)
 {
 printf("Usage:%s [ip address] [any string]n", argv[0]);
 return 1;
 }

 *snd_buf = '';
 strcat(snd_buf, argv[2]);

 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
 {
 perror("socket:");
 exit(1);
 }

 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(SERVPORT);
 inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
 memset(&(server_addr.sin_zero), 0, 8);

 /* create the connection by socket 
 * means that connect "sockfd" to "server_addr"
 * 同步阻塞模式 
 */
 if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
 {
 perror("connect");
 exit(1);
 }

 /* 同步阻塞模式 */
 if (send(sockfd, snd_buf, sizeof(snd_buf), 0) == -1)
 {
 perror("send:");
 exit(1);
 }
 printf("send:%sn", snd_buf);

 /* 同步阻塞模式 */
 if ((recvbytes = recv(sockfd, rcv_buf, MAXDATASIZE, 0)) == -1)
 {
 perror("recv:");
 exit(1);
 }

 rcv_buf[recvbytes] = '';
 printf("recv:%sn", rcv_buf);

 close(sockfd);
 return 0;
} 

显然,代码中的connect, send, recv都是同步阻塞工作模式, 

在结果没有返回时,程序什么也不做。
这种模型非常经典,也被广泛使用。