系统相关
首页 > 系统相关> > Linux系统编程—进程间通信

Linux系统编程—进程间通信

作者:互联网

目录

01. 管道

用于父子进程间(有亲缘关系的进程之间)的通信。

#include <unistd.h>

int pipe(int pipefd[2]);

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>

int pipe2(int pipefd[2], int flags);

/*
On  success,  zero is returned.  On error, -1 is returned, and errno is
set appropriately.
*/

pipefd[0] 是读取端,pipefd[1] 是写入端;从 pipefd[0] 读到的就是往 pipefd[1] 写入的数据。

如果写操作一次写入的数据大小不超过 PIPE_BUF,则此写操作写入的数据与其他进程对同一管道/FIFO的写操作所写入的数据不会交叉;否则可能会发生数据交叉!

对于 pipe2flags 取值如下:

02. FIFO

又叫命名管道,可用于没有亲缘关系的进程间的通信。

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

#include <fcntl.h>           /* Definition of AT_* constants */
#include <sys/stat.h>

/*
 pathname 是相对于目录 dirfd(目录的文件描述符) 的相对路径;
 如果 pathname 为绝对路径,则忽略 dirfd
*/
int mkfifoat(int dirfd, const char *pathname, mode_t mode);

/*
On  success mkfifo() and mkfifoat() return 0.  In the case of an error,
-1 is returned (in which case, errno is set appropriately).
*/

首先通过 mkfifo/mkfifoat 创建 fifo,然后使用 open 打开它,即可通过读写操作进行通信。

如果以非阻塞模式打开 fifo,只读 open 会阻塞进程直到另一个进程以写方式 open 该 fifo,反之亦然。

03. 记录锁

使用 fcntl 能够在一个文件的任意一部分上放置一把锁(劝告式锁)。

#include <fcntl.h>

int fcntl(int fildes, int cmd, .../* struct flock* */);

/*
返回值:
	成功时,返回值不为 -1;
	失败时,返回 -1,并设置 errno
*/

cmd 取值:

flock 结构定义了要获取/删除的锁:

struct flock {
   ...
   short l_type;    /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */
   short l_whence;  /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */
   off_t l_start;   /* Starting offset for lock */
   off_t l_len;     /* Number of bytes to lock */
   pid_t l_pid;     /* PID of process blocking our lock (set by F_GETLK) */
   ...
};

l_type 取值:

l_whence 取值:

l_len 指定了锁区域的大小(字节),0 表示直到文件末尾。

如果一个进程对某个文件区间已持有一把锁,随后该进程在同一区间再加一把锁,那么新锁将替换已有锁!

在设置或释放锁时,系统会合并相邻同类型的锁区间或分裂一个锁区间为多个不同类型的锁区间。如,

// 在一个读锁之后再加一个读锁
|	读锁1		|	读锁2		|	--合并-->		|			读锁		 	|


// 在读锁中间加一个写锁
|		     读锁			 |	 --分裂--> 	 |	读锁1	  |  写锁	 | 读锁2 |

记录锁同时与一个进程和一个 i-node 关联,所以,

fork 创建的子进程不会继承父进程的记录锁。

如果文件描述符没有设置 close-on-exec 标志,则在执行 exec 系列函数时,新程序可以继续使用原有的记录锁;否则则无法使用。

例子:

#include <fcntl.h>

static inline int flock_op(int fd, short type, short whence, off_t offset, off_t len) {
	struct flock lock;
	int ret;

	lock.l_type		= type;
	lock.l_start	= offset;
	lock.l_whence	= whence;
	lock.l_len		= len;

	ret = fcntl(fd, F_SETLK, &lock);
	return ret;
}

int read_lock(int fd, off_t offset, off_t len) {
	return flock_op(fd, F_RDLCK, SEEK_SET, offset, len);
}

int write_lock(int fd, off_t offset, off_t len) {
	return flock_op(fd, F_WRLCK, SEEK_SET, offset, len);
}

int unlock(int fd, off_t offset, off_t len) {
	return flock_op(fd, F_UNLCK, SEEK_SET, offset, len);
}

04. POSIX命名信号量

链接时需指定 -pthread.

创建或打开

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>

// 打开
sem_t *sem_open(const char *name, int oflag);

// 创建
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

/*
On  success,  sem_open() returns the address of the new semaphore;
On error,  sem_open()  returns  SEM_FAILED, with errno set to indicate the error.
*/

name 指定了信号量的名称,以 / 开头,后跟多个非 / 的字符,如 /mysemmode 参数与 open 中的 mode 参数一样,指定了信号量的访问权限(需要可读写);value 指定了信号量的初始值。

oflag 取值:

关闭

#include <semaphore.h>

int sem_close(sem_t *sem);

/*
On  success sem_close() returns 0; on error, -1 is returned, with errno
set to indicate the error.
*/

进程终止或执行 exec 系列函数时会自动关闭信号量。

删除

#include <semaphore.h>

int sem_unlink(const char *name);

/*
On success sem_unlink() returns 0; on error, -1 is returned, with errno
set to indicate the error.
*/

将信号量标记为"一旦所有进程都已关闭该信号量,则删除之"。

PV操作

#include <semaphore.h>

int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

/*
All of these functions return 0 on success; on error, the value of  the
semaphore  is left unchanged, -1 is returned, and errno is set to indi‐
cate the error.
*/

如果信号量的当前值大于 0,则减一返回,否则,

#include <semaphore.h>

int sem_post(sem_t *sem);

/*
sem_post() returns 0 on success; on error, the value of  the  semaphore
is  left  unchanged,  -1  is returned, and errno is set to indicate the
error.
*/

将信号量的当前值加一。

05. POSXI匿名信号量

将信号量放在共享内存区域中,可实现进程间/线程间通信。

PV 操作和命名信号量的一致。

初始化

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

/*
sem_init() returns 0 on success; on error, -1 is returned, and errno is
set to indicate the error.
*/

value 指定了信号量的初始值。

pshared 取值:

销毁

#include <semaphore.h>

int sem_destroy(sem_t *sem);

/*
sem_destroy() returns 0 on success; on error, -1 is returned, and errno
is set to indicate the error.
*/

销毁之后可以重新初始化。

06. POSIX消息队列

链接时需使用 -lrt 选项。

可以使用 pollselectepoll 来监控 POSIX消息队列。

创建或打开

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <mqueue.h>

// 打开
mqd_t mq_open(const char *name, int oflag);

// 创建
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);

/*
On success, mq_open() returns a message queue  descriptor  for  use  by
other message queue functions.  On error, mq_open() returns (mqd_t) -1,
with errno set to indicate the error.
*/

name 指定了队列的名称,以 / 开头,后跟多个非 / 的字符,如 /myqueuemode 参数与 open 中的 mode 参数一样,指定了队列的访问权限(如可读写)。

oflag 取值:

attr 指定了队列的属性,NULL 表示默认属性。

关闭

#include <mqueue.h>

int mq_close(mqd_t mqdes);

/*
On  success  mq_close() returns 0; on error, -1 is returned, with errno
set to indicate the error.
*/

会自动删除已注册的消息通知。

进程终止或执行 exec 时会自动关闭。

删除

#include <mqueue.h>

int mq_unlink(const char *name);

/*
On success mq_unlink() returns 0; on error, -1 is returned, with  errno
set to indicate the error.
*/

将队列标记为"一旦所有进程都已关闭该队列,则删除之"。

属性

#include <mqueue.h>

int mq_getattr(mqd_t mqdes, struct mq_attr *attr);

// oldattr 可为 NULL,不返回之前的属性
int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);

struct mq_attr {
   long mq_flags;       /* Flags: 0 or O_NONBLOCK */
   long mq_maxmsg;      /* Max. # of messages on queue */
   long mq_msgsize;     /* 每条消息的最大大小/字节 */
   long mq_curmsgs;     /* # of messages currently in queue */
};

/*
On  success  mq_getattr()  and  mq_setattr()  return 0; on error, -1 is
returned, with errno set to indicate the error.
*/

设置属性时,只能设置 mq_flags 字段。

发送消息

#include <mqueue.h>

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);

#include <time.h>
#include <mqueue.h>

int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio,
             const struct timespec *abs_timeout);

struct timespec {
   time_t tv_sec;        /* seconds */
   long   tv_nsec;       /* nanoseconds */
};

/*
On  success,  mq_send() and mq_timedsend() return zero; on error, -1 is
returned, with errno set to indicate the error.
*/

msg_prio 指定了消息的优先级(0最低),消息在队列中是按照优先级排序的,高优先级在前,相同优先级的多条消息按照发送时间排序。

abs_timeout 指定了阻塞等待的超时时间(绝对时间),超时时 errno 被设为 ETIMEDOUT

接收消息

#include <mqueue.h>

// msg_prio 可为 NULL,不返回优先级
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);

#include <time.h>
#include <mqueue.h>

ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr,
                  size_t msg_len, unsigned int *msg_prio,
                  const struct timespec *abs_timeout);

/*
 On success, mq_receive() and mq_timedreceive()  return  the  number  of
bytes in the received message; on error, -1 is returned, with errno set
to indicate the error.
*/

获取并删除队列头消息。

msg_len 需大于等于队列的 mq_msgsize 属性,否则会失败返回(errnoEMSGSIZE )。

消息通知

#include <mqueue.h>

int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

union sigval {          /* Data passed with notification */
   int     sival_int;         /* Integer value */
   void   *sival_ptr;         /* Pointer value */
};

struct sigevent {
   int          sigev_notify; /* Notification method */
   int          sigev_signo;  /* Notification signal */
   union sigval sigev_value;  /* Data passed with
                                 notification */
   void       (*sigev_notify_function) (union sigval);
                    /* Function used for thread notification (SIGEV_THREAD) */
   void        *sigev_notify_attributes;
                    /* Attributes for notification thread (SIGEV_THREAD) */
   pid_t        sigev_notify_thread_id;
                    /* ID of thread to signal (SIGEV_THREAD_ID) */
};

/*
On  success mq_notify() returns 0; on error, -1 is returned, with errno
set to indicate the error.
*/

sevpsigev_notify 字段指定了通知方式:

07. XSI IPC

IPC标识符和键

每个 XSI IPC 对象在内核都通过一个非负整数的标识符 (内部名)加以引用;此外,每个 IPC 对象都与一个键(外部名)关联。

为了使不同的进程引用相同的 IPC 对象,可以有如下方式:

  1. 将键指定为 IPC_PRIVATE,在使用 XXXget 操作创建 IPC 对象后,将返回的 IPC 对象标识符存到其他进程可以访问到的地方(如,文件),随后其他进程便可通过该标识符引用相同的 IPC 对象;
  2. 所有的进程通过使用相同的参数调用 ftok 来生成相同的 IPC 键,然后使用该键调用 XXXget 操作来创建或打开既有的 IPC 对象;
#include <sys/types.h>
#include <sys/ipc.h>

// 只取 proj_id 的低 8 bits
key_t ftok(const char *pathname, int proj_id);

/*
On  success,  the  generated key_t value is returned.  On failure -1 is
returned, with errno indicating the error as  for  the  stat(2)  system
call.
*/

权限结构

struct ipc_perm {
   key_t          __key;       /* IPC Key */
   uid_t          uid;         /* Effective UID of owner */
   gid_t          gid;         /* Effective GID of owner */
   uid_t          cuid;        /* Effective UID of creator */
   gid_t          cgid;        /* Effective GID of creator */
   unsigned short mode;        /* Permissions */
   unsigned short __seq;       /* Sequence number */
};

08. XSI 共享内存

为了避免多个进程同时访问共享内存,需要使用额外的同步机制,如信号量等。

创建或打开

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

/*
On success, a valid shared memory identifier is returned.  On error, -1
is returned, and errno is set to indicate the error.
*/

size 指定了共享内存的大小(字节),如果该共享内存已存在,则忽略 size.

shmflg 取值:

附加内存段

将共享内存段附加到进程的虚拟地址空间中。

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

/*
On  success,  shmat() returns the address of the attached shared memory
segment; on error, (void *) -1 is returned, and errno is set  to  indi‐
cate the cause of the error.
*/

shmflg 还可取值:

fork 创建的子进程会继承父进程附加的共享内存段。

分离内存段

将共享内存从进程的地址空间中分离出去。

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

/*
On  success,  shmdt()  returns 0; on error -1 is returned, and errno is
set to indicate the cause of the error.
*/

执行 exec 后,所有已附加的共享内存段都会被分离。

进程终止后,会自动分离共享内存段。

分离并不等于删除。

控制操作

#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

struct shmid_ds {
   struct ipc_perm shm_perm;    /* Ownership and permissions */
   size_t          shm_segsz;   /* Size of segment (bytes) */
   time_t          shm_atime;   /* Last attach time */
   time_t          shm_dtime;   /* Last detach time */
   time_t          shm_ctime;   /* Last change time */
   pid_t           shm_cpid;    /* PID of creator */
   pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
   shmatt_t        shm_nattch;  /* No. of current attaches */
   ...
};

/*
A successful IPC_INFO or SHM_INFO operation returns the  index  of  the
highest used entry in the kernel's internal array recording information
about all shared memory segments.  (This information can be  used  with
repeated  SHM_STAT  operations  to  obtain information about all shared
memory segments  on  the  system.)   A  successful  SHM_STAT  operation
returns  the  identifier  of  the shared memory segment whose index was
given in shmid.  Other operations return 0 on success.

On error, -1 is returned, and errno is set appropriately.
*/

cmd 取值:

如,获取所有的共享内存段信息:(ipcs -m

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

static void fatal(const char* msg) {
	fprintf(stderr, "%s: %s\n", msg, strerror(errno));
	exit(-1);
}

static void waring(const char* msg) {
	fprintf(stderr, "%s: %s\n", msg, strerror(errno));
}

void print_shminfo(const struct shm_info* info ) {
	printf("used_ids: %d\n", info->used_ids);
	printf("shm_tot: %lu\n", info->shm_tot);
	printf("\n");
}

void print_shmds(const struct shmid_ds* ds) {
	printf("shm_segsz: %lu\n", ds->shm_segsz);
	printf("shm_nattach: %lu\n", ds->shm_nattch);
	printf("\n");
}

int main() {
	int ret, n;
	struct shm_info info;
	struct shmid_ds ds;

	n = shmctl(0, SHM_INFO, (struct shmid_ds*)&info);
	if (n == -1) {
		fatal("shmctl");
	}
	print_shminfo(&info);

	for (int i = 0; i < n; i++) {
		ret = shmctl(i, SHM_STAT, &ds);
		if (ret != -1) {
			print_shmds(&ds);
		}
		else {
			waring("shmctl SHM_STAT");
		}
	}
	
	return 0;
}

09. XSI 消息队列

创建或打开

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

/*
If successful, the return value will be the message queue identifier (a
nonnegative integer), otherwise -1 with errno indicating the error.
*/

msgflg 取值:

发送消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

/*
On  failure  msgsnd() returns -1 with errno indicating the error,
otherwise msgsnd() returns 0.
*/

msgp 指向的内容通常具有如下形式:

struct msgbuf {
   long mtype;       /* message type, must be > 0 */
   char mtext[];     /* message data */
};

msgsz 参数指定了 mtext 中的字节数。

msgflg 取值:

接收消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

/*
On  failure  msgrcv() returns -1 with errno indicating the error,
otherwise msgrcv() returns the number  of  bytes actually copied into the mtext array.
*/

msgsz 参数指定了 mtext 所指缓冲区的最大大小。如果消息的大小超过了 msgsz,则不会从队列中删除并返回消息,而是失败返回,并将 errno 置为 E2BIG.

msgtyp 指定了要接收的消息的类型,

msgflg 取值:

控制操作

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

struct msqid_ds {
   struct ipc_perm msg_perm;     /* Ownership and permissions */
   time_t          msg_stime;    /* Time of last msgsnd(2) */
   time_t          msg_rtime;    /* Time of last msgrcv(2) */
   time_t          msg_ctime;    /* Time of last change */
   unsigned long   __msg_cbytes; /* Current number of bytes in queue (nonstandard) */
   msgqnum_t       msg_qnum;     /* Current number of messages in queue */
   msglen_t        msg_qbytes;   /* Maximum number of bytes allowed in queue */
   pid_t           msg_lspid;    /* PID of last msgsnd(2) */
   pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
};

/*
On success, IPC_STAT, IPC_SET, and IPC_RMID  return  0.   A  successful
IPC_INFO  or  MSG_INFO  operation returns the index of the highest used
entry in the kernel's internal array recording  information  about  all
message  queues.   (This information can be used with repeated MSG_STAT
operations to obtain information about all queues on  the  system.)   A
successful MSG_STAT operation returns the identifier of the queue whose
index was given in msqid.

On error, -1 is returned with errno indicating the error.
*/

cmd 取值:

10. 内存映射

有两种内存映射:

每种映射又可分为:

创建映射

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

/*
On success, mmap() returns a pointer to the mapped area.  On error, the
value MAP_FAILED (that is, (void *) -1) is returned, and errno  is  set
to indicate the cause of the error.
*/

如果 addr 为 NULL,则会自动将映射放到进程地址空间中合适的地方。

length 指定了要映射的字节数。

prot 取值:

flags 取值:

fd 指定要映射哪个文件、offset 指定要映射的文件区域的起始偏移量(匿名映射不使用)。

解除映射

#include <sys/mman.h>

int munmap(void *addr, size_t length);

/*
On  success,  munmap() returns 0.  On failure, it returns -1, and errno
is set to indicate the cause of the error (probably to EINVAL).
*/

addr 指定要删除的映射的起始地址,需是分页边界对齐。

length 指定要删除的映射的大小,会向上舍入到分页的整数倍。

进程终止或执行 exec 后会自动解除映射。

文件映射

可使用如下操作来同步共享文件映射和底层文件内容:

#include <sys/mman.h>

int msync(void *addr, size_t length, int flags);

/*
On success, zero is returned.  On error, -1 is returned, and  errno  is
set appropriately.
*/

addrlength 指定了要同步的映射区域,addr 需是分页边界对齐的,length 会向上舍入到分页大小的整数倍。

flags 取值:

匿名映射

11. 套接字

创建

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

/*
On  success,  a  file  descriptor  for  the new socket is returned.  On
error, -1 is returned, and errno is set appropriately.
*/

domain 常用值:AF_INET, AF_INET6, AF_UNIX, AF_NETLINK, AF_PACKET.

type 常用值:SOCK_STREAM, SOCK_DGRAM, SOCK_RAW.

可以在 type 中位或如下值:

protocol 指定要使用的协议,对于 TCP、UDP、Unix域套接字,将其设为 0 即可。

绑定地址

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

struct sockaddr {
   sa_family_t sa_family;
   char        sa_data[14];
}

/*
On  success,  zero is returned.  On error, -1 is returned, and errno is
set appropriately.
*/

ipv4地址结构:

struct sockaddr_in {
   sa_family_t    sin_family; /* address family: AF_INET */
   in_port_t      sin_port;   /* port in network byte order */
   struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
   uint32_t       s_addr;     /* address in network byte order */
};

ipv6地址结构:

struct sockaddr_in6 {
   sa_family_t     sin6_family;   /* AF_INET6 */
   in_port_t       sin6_port;     /* port number */
   uint32_t        sin6_flowinfo; /* IPv6 flow information */
   struct in6_addr sin6_addr;     /* IPv6 address */
   uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */
};

struct in6_addr {
   unsigned char   s6_addr[16];   /* IPv6 address */
};

unix地址结构:

struct sockaddr_un {
   sa_family_t sun_family;               /* AF_UNIX */
   char        sun_path[108];            /* pathname */
};

监听

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);

/*
On  success,  zero is returned.  On error, -1 is returned, and errno is
set appropriately.
*/

backlog 指定了等待连接队列的最大大小。

接受连接

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sys/socket.h>

int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

/*
On  success,  these system calls return a nonnegative integer that is a
descriptor for the accepted socket.  On  error,  -1  is  returned,  and
errno is set appropriately.
*/

addrlen 需初始化为 addr 指向空间的大小,返回时,其中保存对端地址的大小。如对对端地址不感兴趣,可将 addraddrlen 设为 NULL.

flags 可取值:

发起连接

#include <sys/types.h> 
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

/*
If  the connection or binding succeeds, zero is returned.  On error, -1
is returned, and errno is set appropriately.
*/

对于基于连接的套接字,它会连接到 addr 指定的对端。

对于 SOCK_DGRAM 套接字,addr 指定了默认发送操作的对端。

关闭

#include <unistd.h>

int close(int fd);

/*
close()  returns  zero on success.  On error, -1 is returned, and errno
is set appropriately.
*/

半关闭

#include <sys/socket.h>

int shutdown(int sockfd, int how);

/*
On  success,  zero is returned.  On error, -1 is returned, and errno is
set appropriately.
*/

how 取值:

shutdown 并不会关闭套接字描述符。

无论该套接字上是否还关联着其他的描述符,shutdown 都会关闭套接字通道,这意味着无法通过其他描述符进行读/写操作。如,

fd2 = dup(sockfd);

shutdown(sockfd, SHUT_RD);

read(fd2, buf, len);	// 失败!!

发送数据

也可以使用 write 系列操作。

send

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

/*
On success, it returns the number of bytes sent.  On error,  -1
is returned, and errno is set appropriately.
*/

send(sockfd, buf, len, flags) 等价于 sendto(sockfd, buf, len, flags, NULL, 0).

flags 取值:

sendto

#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

/*
On success, it returns the number of bytes sent.  On error,  -1
is returned, and errno is set appropriately.
*/

flagssend.

sendmsg

#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

struct msghdr {
   void         *msg_name;       /* optional address */
   socklen_t     msg_namelen;    /* size of address */
   struct iovec *msg_iov;        /* scatter/gather array */
   size_t        msg_iovlen;     /* # elements in msg_iov */
   void         *msg_control;    /* ancillary data */
   size_t        msg_controllen; /* ancillary data buffer len */
   int           msg_flags;      /* flags (unused) */
};

struct iovec {                    /* Scatter/gather array items */
   void  *iov_base;              /* Starting address */
   size_t iov_len;               /* Number of bytes to transfer */
};

/*
On success, it returns the number of bytes sent.  On error,  -1
is returned, and errno is set appropriately.
*/

flagssend.

接收数据

也可使用 read 系列操作。

recv

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

/*
It returns  the  number  of bytes received, or -1 if an error
occurred.  In the event of an error,  errno  is  set  to  indicate  the
error.
*/

recv(fd, buf, len, flags) 等价于 recvfrom(fd, buf, len, flags, NULL, 0).

flags 取值:

recvfrom

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

/*
It returns  the  number  of bytes received, or -1 if an error
occurred.  In the event of an error,  errno  is  set  to  indicate  the
error.
*/

addrlen 需初始化为 src_addr 指向空间的大小,返回时,其中保存对端地址的大小。如对对端地址不感兴趣,可将 src_addraddrlen 设为 NULL.

flagsrecv.

recvmsg

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

/*
It returns  the  number  of bytes received, or -1 if an error
occurred.  In the event of an error,  errno  is  set  to  indicate  the
error.
*/

flagsrecv.

返回的 msg->msg_flags:

发送文件

#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

/*
If  the  transfer was successful, the number of bytes written to out_fd
is returned.  Note that a successful call to sendfile() may write fewer
bytes  than  requested; the caller should be prepared to retry the call
if there were unsent bytes.

On error, -1 is returned, and errno is set appropriately.
*/

in_fd 读取数据,并写到 out_fd 中,而这一切都是在内核空间完成的,不需要通过用户空间!

offset 指定了源文件的起始偏移量,为 NULL 表示当前偏移量;返回时会更新 offset 以指向新的偏移。但 sendfile 并不会更改源文件的偏移量,但会修改目标文件的偏移量。

count 指定了最多发送多少字节的数据。

自 Linux 2.6.33 之后,out_fd 可以是任何文件,而不必是套接字描述符!

标签:struct,Linux,int,errno,编程,间通信,error,include,returned
来源: https://blog.csdn.net/gaoZhuanMing/article/details/114494247