Linux 下读写函数的介绍(系统调用、c库函数、socket通信)

一、系统调用读写函数
1、write函数
原型:ssize_t write (int fd, const void * buf, size_t count);
说明:write()会把参数buf 所指的内存写入count 个字节到参数fd 所指的文件内.
返回值:
(1)如果顺利write()会返回实际写入的字节数.
(2)当有错误发生时则返回-1, 错误代码存入errno 中.
错误代码:
EINTR 此调用被信号所中断.
EAGAIN 当使用不可阻断I/O 时 (O_NONBLOCK), 若无数据可读取则返回此值.
EADF 参数fd 非有效的文件描述词, 或该文件已关闭.

2、read函数
原型:ssize_t read(int fd, void * buf, size_t count);
说明:read()会将文件fd 上的数据读取count字节存储到参数buf
返回值:
(1)如果成功,返回读取的字节数;
(2)如果出错,返回-1并设置errno;
(3)如果在调read函数之前已是文件末尾,则返回0
如果顺利 read()会返回实际读到的字节数, 最好能将返回值与参数count 作比较,
若返回的字节数比要求读取的字节数少, 则有可能读到了文件尾

二、c标准库读写库函数
1、fread函数
原型;size_t fread(void *ptr,size_t size,size_t nitems,FILE *stream);
说明:阻塞等待获取指定数量的数据
2、fwrite函数
原型;siize_t fwrite(const void *ptr,size_t size,size_t nitems,FILE *stream);、
说明:阻塞等待输入的数据量达到指定量后输出
3、fgetc函数
原型:int fgetc(FILE *stream);
说明:获取一个字符
4、fputc函数
原型:int fputc(int c, FILE *stream);
说明:往指定流写入一个字符
5、getchar函数
原型:int getchar(void);
说明;getchar 函数的作用就相当于 getc(stdin),它直接从标准输入里读取下一个字符。
6、putchar函数
原型:int putchar(int c);
说明:往标准输出流中写入数据
7、getc函数
原型:int getc(FILE *stream);
说明:getc 函数的作用和 fgetc 函数一样,但是,getc 函数可以被实现为宏
8、putc函数
原型:int putc(int c, FILE *stream);
9、fgets函数
原型:char *fgets(char *s, int size, FILE *stream);
说明:
fgets 函数把读到的字符写到 s 指向的字符串里,直到:
1)遇到换行符,则停止读入字符,并将遇到的换行符一起传递给接收字符串,再加上一个表示结尾的空字节 \0;
2)已经传输了 n-1 个字符,则加上一个空字节 \0 结尾后,停止读入字符;
3)到达文件尾(EOF)。
10、fputs函数
原型;int fputs(const char *s, FILE *stream);
11、puts函数
原型:int puts(const char *s);

示例:

int count;
char buf[1024];
char c;

printf("test fgetc and fputc\n");
c = fgetc(stdin);
fputc(c,stdout);
fputc('\n', stdout);

printf("test fgets and fputs\n");
fgets(buf, 1024, stdin);
fputs(buf, stdout);
fputs("\n", stdout);

printf("test fread and fwrite\n");
fread(buf, 1, 10, stdin);
fwrite(buf, 1, 10, stdout);

三、socket套接字读写函数
#include <sys/types.h>
#include <sys/socket.h>

UDP 读写

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, 
				struct sockaddr *src_addr, socklen_t *addrlen);
sockfd:之前创建的socket文件描述符,从这个文件描述符中读取数据
buf:用来存放接收数据的缓冲区
len:该缓冲区的大小,这里注意有坑,需要用sizeof(buf)-1,因为这里还需要一个空间的大小的来存放'\0'。
flags:一般设置为0
src_addr:因为UDP没有通信连接的概念,因此每次接收数据都需要获取到发送端的socket地址(下面的sendto函数也是类似),src_addr就是发送端的源地址,对于服务器来说,这也就是客户端来发送的地址。从sockfd中读取到发送端的socket地址放到这个src_addr结构体中
addrlen:源地址结构体的大小,注意这里的类型是socklen_t*,需要&sizeof(src_addr),这也是一个输入输出型参数
返回值:失败返回-1,成功返回实际接收数据的大小。		
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, 
				const struct sockaddr *dest_addr, socklen_t addrlen);

sockfd:之前创建的socket文件描述符
buf:要发送的数据在buf当中
len:这里和recvfrom不同的是,此处不需要sizeof(buf)-1,因为这里的buf数组可能不是满的,它的中间可能有'\0'sizeof(buf)得到的是整个缓冲区的大小,strlen(buf)得到的大小是到第一个'\0'的大小,所以此处需要用的是strlen(buf)
flags:一般设置为0
dest_addr:指要把数据发送给哪个目的IP,如果是客户端给服务器发消息,那么dest_addr就是服务器的socket地址
addrlen:目的IP的大小,注意这里又有和recvfrom不同的地方,前面的addrlen的类型的是指针,这里不是指针,所以直接用sizeof(dest_addr)即可,因为这不是一个输入输出型参数
返回值:失败返回-1,成功返回传送的数据的大小

注:
recvfrom函数和sendto函数还可以用于面向连接的socket读写,只需要把最后两个参数都设置为NULL就可以了,因为我们已经知道对端的socket地址了,这就有点像下面要将的recv和send了。
TCP 读写

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
sockfd是之前创建的文件描述符,并且是已经命名过(bind)和设置监听了的(listen)
buf:用来存放接收数据的缓冲区
len:该缓冲区的大小,注意和recvfrom中的一样也要留一个空间给'\0'
flags:一般置为0

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd是之前创建的文件描述符,并且是已经命名过(bind)和设置监听了的(listen)
buf:发送的是buf缓冲区中的数据
len:缓冲区实际的有效大小(字符串就用strlen)
flags:一般置为0

通用数据读写

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
socket编程接口还提供了一对通用的数据读写接口。它们不仅能用于TCP,也能用于UDP
sockfd参数指定被操作的目标socket
msg参数是msghdr结构体指针,该结构体定义如下:
struct msghdr {
    void*         msg_name;       /* socket地址 */
    socklen_t     msg_namelen;    /* socket地址长度 */
    struct iovec* msg_iov;        /* 分散的内存块 */
    size_t        msg_iovlen;     /* 分散的内存块数量 */
    void*         msg_control;    /* 指向辅助数据的起始位置 */
    size_t        msg_controllen; /* 辅助数据的大小 */
    int           msg_flags;      /* 复制函数中的flags参数,并在调用过程中更新 */
};

struct iovec {                    
    void  *iov_base;              /* 内存起始地址 */
    size_t iov_len;               /* 这块内存的长度 */
};
msg_name成员指向一个socket地址结构变量。它指定通信对方的socket地址。对于面向连接的TCP协议,该成员没有意义,必须被置为NULL
msg_namelen成员指定了msg_name成员所指的socket地址的长度
msg_iov成员指向一个iovec结构体,该结构体封装了一块内存的起始位置和长度
msg_iovlen指定这样的结构体有几个。对于recvmsg而言,数据将被读取并存放在msg_iovlen块分散的内存中,这些内存的位置和长度由msg_iov指向的数组指定,这称为分散读;对于sengmsg而言,msg_ioven块分散内存中的数据将被一并发送,这称为集中写。
msg_control和msg_controllen用于辅助数据的传送
msg_flags成员无需设定,它会复制传入的flags参数。recvmsg还会在调用结束前,将某些更新后的标志设置到msg_flags中。

与文件读写一致的读写函数
#include <unistd.h>
ssize_t read (int fd, void *buf, size_t count);
ssize_t write (int fd, const void *buf, size_t count);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值