码迷,mamicode.com
首页 > 系统相关 > 详细

【linux高级程序设计】(第十四章)TCP高级应用

时间:2015-08-04 00:31:13      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:

文件I/O方式比较

1.阻塞式文件I/O

进程从调用函数开始,直到返回这段时间都处于阻塞状态。

技术分享

2.非阻塞式文件I/O

如果当前没有数据可操作,将不阻塞当前进程,而是立即返回一个错误信息。需要反复尝试。

技术分享

3.多路复用I/O

仍然是阻塞方式等待,但是可以同时等待多个文件描述符。

技术分享

4.信号驱动I/O

异步方式,等到数据准备好后通知处理进程,不需要重复询问,效率高。

技术分享

 

 

I/O阻塞与非阻塞操作

阻塞方式:默认情况下read/write和 把flag设为0的recv/send

非阻塞方式:如果没有数据,立刻返回-1表示失败,并修改系统全局变量errno的值为EAGAIN,表示数据未准备好。

      通过设置recv的MSG_DONTWAIT标志可以实现。如果设置socket的文件描述符的属性为非阻塞,将导致后续所有针对该文件描述符的操作都为非阻塞。

 

例子:

服务器端:接收非阻塞,发送阻塞。 可以连续发送多条。如果对方发送的很多数据过来,也会一次性接收。

客户端:发送、接收都阻塞。这个例子里面,接收端一定是收一条、发一条这样交替着的。如果服务器发送了多条,则会分开接收到。

奇怪:这个例子里面,接收端也绑定了自己的地址,而之前的例子里却没有绑定。两者都实现了通信,为什么呢?

 

服务器代码:

#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#define BUFSIZE 128

int main(int argc, char *argv[])
{
    int server_sockfd, client_sockfd;
    int server_len, client_len;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;
    int i, byte;
    char char_send[BUFSIZE];
    //创建socket对象 阻塞
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    server_address.sin_family = AF_INET;
    //从argv[1]提取IP地址
    if(inet_aton(argv[1],(struct in_addr*)&server_address.sin_addr.s_addr) == 0)
    {
        perror(argv[1]);
        exit(EXIT_FAILURE);
    }
    server_address.sin_port = htons(7838);  //使用特定端口
    server_len = sizeof(server_address);
    //绑定IP信息
    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
    //监听网络
    listen(server_sockfd, 5);
    printf("server waiting for connect\n");
    client_len = sizeof(client_address);
    //等待连接
    client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,(socklen_t *)&client_len);
    for(i = 0; i < 5; i++)
    {
        memset(char_send, \0, BUFSIZE);
        printf("input message to send:");
        fgets(char_send, BUFSIZE, stdin);  //阻塞在终端,接收用户输入数据
        //发送
        if((byte = send(client_sockfd, char_send, strlen(char_send), 0)) == -1)
        {
            perror("send");
            exit(EXIT_FAILURE);
        }
        memset(char_send, \0, BUFSIZE);
        //非阻塞接收
        byte = recv(client_sockfd, char_send, BUFSIZE, MSG_DONTWAIT);
        if(byte > 0)
        {
            printf("get %d message:%s", byte, char_send);
            byte = 0;
        }
        else if(byte < 0)
        {
            if(errno == EAGAIN)
            {
                errno = 0;
                continue;
            }
            else
            {
                perror("recv");
                exit(EXIT_FAILURE);
            }
        }
    }
    //关闭socket对象
    shutdown(client_sockfd, 2);
    shutdown(server_sockfd, 2);
}

客户端代码:

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<resolv.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<fcntl.h>
#define MAXBUF 128
int main(int argc, char **argv)
{
    int sockfd, ret, i;
    struct sockaddr_in dest, mine;
    char buffer[MAXBUF + 1];
    //创建socket对象
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket");
        exit(EXIT_FAILURE);
    }
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(7838);  //服务器的特定端口,与服务器端设置一致
    //获取服务器IP地址,由argv[1]指定
    if(inet_aton(argv[1], (struct in_addr *)&dest.sin_addr.s_addr) == 0)
    {
        perror(argv[1]);
        exit(EXIT_FAILURE);
    }
    bzero(&mine, sizeof(mine));
    mine.sin_family = AF_INET;
    mine.sin_port = htons(7839);   //本地端口
    //本地IP地址,由argv[2]指定
    if(inet_aton(argv[2], (struct in_addr *)&mine.sin_addr.s_addr) == 0)
    {
        perror(argv[2]);
        exit(EXIT_FAILURE);
    }
    //绑定自己的IP地址信息
    if(bind(sockfd, (struct sockaddr *)&mine, sizeof(struct sockaddr)) == -1)
    {
        perror("bind");
        exit(EXIT_FAILURE);
    }
    //发起连接
    if(connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) != 0)
    {
        perror("Connect");
        exit(EXIT_FAILURE);
    }
    //设置sockfd描述符为非阻塞
    if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1)
    {
        perror("fcntl");
        exit(EXIT_FAILURE);
    }
    while(1)
    {
        bzero(buffer, MAXBUF + 1);
        //接收
        ret = recv(sockfd, buffer, MAXBUF, 0); //因为设置socket非阻塞,故此操作非阻塞
        if(ret > 0)
        {
            printf("get %d message:%s", ret, buffer);
            ret = 0;
        }
        else if(ret < 0)
        {
            if(errno == EAGAIN)
            {
                errno = 0;
                continue;
            }
            else
            {
                perror("recv");
                exit(EXIT_FAILURE);
            }
        }
        memset(buffer, \0, MAXBUF + 1);
        printf("input message to send:");
        fgets(buffer, MAXBUF, stdin);  //在接收到数据后阻塞在终端,向对方发
        if((ret = send(sockfd, buffer, strlen(buffer), 0)) == -1) //发送数据
        {
            perror("send");
            exit(EXIT_FAILURE);
        }
    }
    close(sockfd);
    return 0;
}

 

我在同一台虚拟机的不同终端做实验

服务器端结果:

技术分享

客户端结果:

技术分享

 

【linux高级程序设计】(第十四章)TCP高级应用

标签:

原文地址:http://www.cnblogs.com/dplearning/p/4700621.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!