Linux IO模型漫谈(3) -- 阻塞式IO实现

在理解代码前有几个函数先说一下:

1 sockaddr_in 套接字地址结构


1

2

3

4

5

6

7

8

9

10

struct sockaddr_in {

    uint8_t         sin_len;        //长度字段,这个sockaddr_in结构的长度,一般不用设置和检查它

    sa_family_t     sin_family;     //协议族,TCP,UDP等协议族就设置为AF_INET 

    in_port_t       sin_port;       //端口号

     

    struct in_addr  sin_addr;       //32位的IPv4地址

     

    char            sin_zero(8);    //未使用

 

}

POSIX规范只需要指定其中的sin_family, sin_port, sin_addr三个字段

这个结构非常重要!!

2 socket函数(创建套接字)

#include <sys/socket.h>

int socket(int family, int type, int protocol)

参数解释:

family:协议族,和sockaddr_in中的sin_family一个意思

type: 指明套接字类型

Protocol:通常赋值为0

 

这个函数是所有套接字编程的入口,创建套接字。

3 htons函数

这个函数是将本地字节序列转换为网络字节序列,简单来说,就是将一个数的高低位互换

(如12 34 -> 3412)

这个函数在给servaddr_in赋值的时候会用到

下面这个程序包含了基本的IO操作,说明以注释的形式加在代码中;

服务器端:

#include <stdio.h>     //这个头包含了最简单的输入和输出
#include <sys/types.h>    //这个头包含了系统调用的大量数据结构
#include <sys/socket.h>   //这个头包含了socket的结构
#include <netinet/in.h>   //这个头包含了internet地址解析的一些数据结构
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int listenfd, portno;  //文件描述符
    int clifd, clilen;
    struct sockaddr_in serv_addr,cli_addr;  //socketadd_in定义在netinet/in.h中
    listenfd = socket(AF_INET, SOCK_STREAM, 0);  //创建一个套接字

    bzero((char *) &serv_addr, sizeof(serv_addr));  //初始化
    serv_addr.sin_family = AF_INET;     //设置协议族
    serv_addr.sin_port = htons(7777);      //设置端口
    serv_addr.sin_addr.s_addr = INADDR_ANY;  //设置socket的另一端的地址信息,由于这里是server程序,因此设置为ANY

    bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); //绑定地址,将本地协议地址赋予一个套接字
    listen(listenfd, 5);  //监听socket,第二个参数规定了内核应该为相应套接字排队的最大连接数个数,不要设置为0

    clilen = sizeof(cli_addr);
    clifd = accept(listenfd, (struct sockaddr *) &cli_addr, &clilen); //当有客户端连接的时候,进入连接队列

    char buffer[256];
    bzero(buffer, 256);
    read(clifd, buffer, 255);   //读取客户端发送的消息
    printf("The Message is:%s\r\n", buffer);

    write(clifd, "I get the message", 17); //往客户端发送消息

    close(clifd);
    close(listenfd);
    return 0;

}

server的流程基本是这样的:

客户端:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int socketfd;
    socketfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;

    bzero((char *)&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(7777);

    connect(socketfd,(struct sockaddr *)  &serv_addr, sizeof(serv_addr));

    write(socketfd, "client message", 14);

    char buffer[256];
    bzero(buffer, 256);
    read(socketfd, buffer, 255);

    printf("server return message:%s\r\n", buffer);

    return 0;
}

客户端的流程如下;

时间: 2024-11-10 00:43:46

Linux IO模型漫谈(3) -- 阻塞式IO实现的相关文章

Linux IO模型漫谈(5)- IO复用模型之select

首先需要了解的是select函数: select函数 #include<sys/select.h> #include<sys/time.h> int select (int maxfd , fd_set *readset ,fd_set *writeset, fd_set *exceptionset , const struct timeval * timeout); 返回:就绪描述字的正数目,0--超时,-1--出错   参数解释: maxfd: 最大的文件描述符(其值应该为最大

Linux IO模型漫谈(1)

基础知识 Linux将所有外部设备都看做一个文件来进行操作.因此,linux对所有外部设备的操作都可以看做是文件的操作.文件的操作当然需要有个标示描述它,这就是文件描述符(file descriptor). linux的IO操作如何形象理解呢? 我们说网络socket的read()是一个IO操作命令,具体流程是这样的: 应用程序调用read命令,通知内核需要做读取数据操作 内核创建一个文件描述符 内核从物理层收到读数据的命令,从网络中获取数据包 数据包传递到TCP/IP层,解析数据包的头 内核将

Linux IO模型漫谈(2)

不管Linux的IO模型的阻塞同步分类是如何分类,几种IO模型的具体实现是确定的.这里借用<Unix 网络编程:卷一>的图片说明. 1 阻塞式IO模型 这个模型也是最容易理解的 程序调用和我们基本的程序编写是一致的: fd = connect() write(fd) read(fd) close(fd) 程序的read必须在write之后执行,当write阻塞住了,read就不能执行下去 2 非阻塞IO模型 从图中可以看出来,这是一个轮询的过程 每次用户询问内核是否有数据报准备好(文件描述符缓

Linux IO模型漫谈(6)- 信号驱动IO模型

Unix上有定义了许多信号.源自Berkeley的实现使用的是SIGIO信号来支持套接字和终端设备上的信号驱动IO. 信号驱动IO模型主要是在UDP套接字上使用,在TCP套接字上几乎是没有什么使用的. 在UDP上,SIGIO信号会在下面两个事件的时候产生: 1 数据报到达套接字 2 套接字上发上一部错误 因此我们很容易判断SIGIO出现的时候,如果不是发生错误,那么就是有数据报到达了. 而在TCP上,由于TCP是双工的,它的信号产生过于平凡,并且信号的出现几乎没有告诉我们发生了什么事情.因此对于

网络编程中阻塞式IO的真正含义到底是什么

问题描述 这两天在看socket编程,可以说这方面是个新手,其中看到了nio,网上有很多文章介绍了nio相对于多线程处理网络链接(每建立一个socket链接,服务器便会开启一个线程来对此socket单独处理和客户端的通信)的优点.因为nio是事件驱动,不会发生Socket读取流数据时的阻塞.我想问的是这里所说的读取流数据的阻塞是我们平时所说的线程进入阻塞态吗?当一个线程单独处理一个客户端请求时,它需要等待客户端向它的输出流写入数据,完后服务器端处理此socket的线程才能读取数据,如果客户端未写

Java IO:操作系统的IO处理过程以及5种网络IO模型

操作系统如何处理IO Linux 会把所有的外部设备都看成一个文件来操作,对外部设备的操作可以看成是对文件的操作. 我们对一个文件的读写,都会通过内核提供的系统调用,内核会给我们返回一个 File Descriptor,这个描述符是一个数字,指向内核的一个结构体,我们应用程序对文件的读写就是对描述符指向的结构体的读写. 系统调用是如何完成IO操作? Linux 会把内存分为 内核区和用户区.Linux 的内核区会帮我们管理所有的硬件资源,并且会提供系统调用,我们应用程序的读操作,就会通过系统调用

《Java NIO文档》非阻塞式服务器

即使你知道Java NIO 非阻塞的工作特性(如Selector,Channel,Buffer等组件),但是想要设计一个非阻塞的服务器仍然是一件很困难的事.非阻塞式服务器相较于阻塞式来说要多上许多挑战.本文将会讨论非阻塞式服务器的主要几个难题,并针对这些难题给出一些可能的解决方案. 查找关于非阻塞式服务器设计方面的资料实在不太容易,所以本文提供的解决方案都是基于本人工作和想法上的.如果各位有其他的替代方案或者更好的想法,我会很乐意听取这些方案和想法!你可以在文章下方留下你的评论,或者发邮件给我(

IO模型

一.   简介 介绍同步.异步.阻塞.非阻塞的区别. 介绍五中IO模型. 介绍IO多路复用使用的Ractor设计模式:介绍异步IO的Proactor设计模式,以及Proactor的流程. IO模型的对比.   二.   同步.异步.阻塞.非阻塞 1.  阻塞(blocking)VS非阻塞(non-blocking) 依读操作为例:当用户线程发起一个IO读请求时,内核会去查看要读取的数据是否就绪,对于阻塞IO来说,如果数据没有就绪,则会一直在那等待,直到数据就绪:对于非阻塞IO来说,如果数据没有

[转]高性能IO模型浅析

高性能IO模型浅析 转自:http://www.cnblogs.com/fanzhidongyzby/p/4098546.html 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK.注意这里所说的NIO并非Java的NIO(New IO)库. (3)IO多路复用(IO Mul