1.3 C/S模式

  TCP允许程序员在两个应用程序之间建立连接并来回传递数据,这种应用程序可以在同一台机器上,也可以在不同的机器上运行。TCP并没有规定应用程序在什么时间进行交互以及为什么要进行交互,也没有规定程序员如何组织这些应用程序。在实践中,有一种应用程序的组织方式在TCP的使用中占据着主要地位,就是C/S模式,即Client/Server模式。

  C/S模式要求应用程序分为两个部分:一个负责通过发送请求来启动通信,称为Client,另一个负责对请求进行应答,称为Server。Client和Server通常运行于不同的机器上。

  Server端代码示例如下:

fd = socket(AF_INET, SOCK_STREAM, 0);
...
local_addr.sin_family = AF_INET;//使用IPv4协议
local_addr.sin_port = htons(80);//监听80端口
local_addr.sin_addr.s_addr = 192.168.1.101;//绑定IP地址,INADDR_ANY是任意地址
bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr));
...
listen(fd, 10);
...
while(1) {
    sockfd = accept(fd, (struct sockaddr *)&addr, &addrlen);
    ...
    while(1) {
        rlen = read(sockfd, buf, len);
  if (rlen == 0) {
                break;
        }
   ...
        wlen = write(sockfd, buf, len);
        ...
  }
    close(sockfd);
    ...
}
...
close(fd);
...
  Server端代码详解:

  使用socket系统调用可以获得一个socket的文件描述符,利用这个描述符就可以控制socket的行为。示例中的调用方法可以产生一个使用TCP协议的socket。

  bind系统调用用于将socket绑定到指定的IP和端口上,这样Server端的TCP就会使用这个指定的IP-端口对来提供服务。这样的IP-端口对必须对外发布,使得想要与server进行通信的client端知道如何找到server并与之建立连接。同样的IP-端口对只能bind一次。

  listen系统调用设置socket为监听状态,并设置等待建立的连接的队列长度为10。

  accept系统调用在没有SYN请求到来时会阻塞,有SYN请求到来并且三次握手完成后会解除阻塞,并产生一个新的socket sockfd,与client端进行数据收发的通信由sockfd完成。同时有多个请求到来并且完成三次握手时,未被accept的连接会放入队列中等待accept,这个队列的长度由listen系统调用决定。

  read系统调用将client发送的数据读取出来,读出的数据长度为0意味着client端已经关闭了连接。

  write系统调用将server端的数据发送给client端。

  close系统调用会释放socket,在释放前TCP会关闭与client之间的连接。

  完成与client端的一次通信后,server会重新调用accept,等待新连接到来。  

  client端代码示例:

fd = socket(AF_INET, SOCK_STREAM, 0);
daddr.sin_family = AF_INET;
daddr.sin_port = htons(80);
daddr.sin_addr.s_addr = 192.168.1.101;//Server IP地址

connect(fd, (struct sockaddr *)&daddr, sizeof(daddr));
...
while(1) {

    wlen = write(sockfd, buf, len);

    ...
    rlen = read(sockfd, buf, len);
    if (rlen == 0) {
        break;
    }
    ...
}
close(fd);

   client端代码详解: 

  socket系统调用产生一个client端的TCP socket,在整个通信过程中client只使用这一个socket。

  connect系统调用用于向server发起连接请求,对于TCP则会发送SYN请求,开始三次握手过程。这个过程完毕后connect会返回。

  其余的系统调用的功能与server端一致。

  client也可以使用bind系统调用,不过client使用bind是绑定通信时使用的源端口号。如果不调用bind则在调用connect时TCP会自动选取一个端口号作为源端口。

  使用上述模型就可以利用TCP完成数据通信了。对代码的解说也能使得socket API接口对TCP行为的影响明晰一些。但还有很多问题无法明确,例如:socket系统调用究竟对TCP做了什么?TCP如何选取client的源端口号?对于这样的问题,让我们到Linux内核代码中去寻找答案吧!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值