Linux进程通信

2022-06-17 14:37:51 浏览数 (1)

Linux进程通信

  • 1 管道(pipe)
    • 1.1 无名管道
      • 1.1.1 概念和相关知识
      • 1.1.2 相关函数
    • 1.2 命名管道
      • 1.2.1 概念及相关知识
      • 1.2.2 相关函数
  • 2 信号量(semaphore)
    • 2.1 无名信号量
    • 2.2 有名信号量
      • 2.2.1 概念和相关知识
      • 2.2.2 相关函数
        • 2.2.2.1 创建信号量
        • 2.2.2.2 打开信号量
        • 2.2.2.3 信号量操作
  • 3 消息队列(message queue)
    • 3.1 相关函数
      • 3.1.1 创建消息队列
      • 3.1.2 发送消息
      • 3.1.3 接收消息
      • 3.1.4 控制消息队列
  • 4 信号(signal)
    • 4.1 相关函数
      • 4.1.1 signal函数(自定义信号处理)
      • 4.1.2 常见信号
      • 4.1.3 sigaction函数
      • 4.1.4 信号的阻塞
      • 4.1.5 信号的发送kill函数
      • 4.1.6 信号的发送raise函数
      • 4.1.7 信号的发送abort函数
      • 4.1.8 信号的发送pause函数
      • 4.1.9 信号的发送alarm函数
  • 5 共享内存(shared memory)
    • 5.1 相关函数
      • 5.1.1 创建/获取共享内存shmget函数
      • 5.1.2 将共享内存连接到进程地址空间shmat函数
      • 5.1.3 将共享内存段与当前进程脱离shmdt函数
      • 5.1.4 共享内存控制shmctl函数
  • 6 套接字(socket)
    • 6.1 相关函数
      • 6.1.1 socket函数
      • 6.1.2 bind函数
      • 6.1.3 connect函数
      • 6.1.4 listen函数
      • 6.1.5 accept函数
      • 6.1.6 recv函数
      • 6.1.7 recvfrom函数
      • 6.1.8 send函数
      • 6.1.9 sendto函数
      • 6.1.10 close函数

1 管道(pipe)

管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,是只存在于内存中的文件,本质是内核的一块缓冲。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。管道是单向的、先进先出的、无结构的、固定大小字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。

1.1 无名管道

1.1.1 概念和相关知识

无名管道只能用于具有亲缘关系的进程之间的通信,通常一个管道由一个进程创建,然后实现两个进程间的通信时必须通过fork创建子进程,实现父子进程之间的通信。 半双工通信模式,具有固定的读端和写端:传输方向只能是一个方向。 管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数,因为管道在文件系统中并不存在对应的文件,所以不支持lseek()等操作。

(1) 管道的大小

管道的大小是PIPE_BUF(ubuntu操作系统为65536)

  1. 从管道中读取数据 写端存在时,当管道无数据时,读操作就会阻塞。 写端存在时,当读端请求读取的数据大于管道中的数据时,此时读取管道中实际的数据。当读端请求读取的数据小于管道中的数据时,此时返回请求读取的数据。 当读一个写端已经被关闭的管道时,在所有数据都被读取后,read返回0,以指示达到了文件结束处。
  2. 向管道中写数据 读端存在时,向管道中写入数据时,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。若有多个进程同时写一个管道(FIFO),则数据可能会与其他写操作的数据交错(需要借助进程间同步/互斥机制)。 读端存在时,如果管道缓冲区数据到达PIPE_BUF,读进程不读走管道缓冲区中的数据,那么写进程将会一直阻塞。 如果写一个读端已经被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write出错返回,errn设置为EPPIPE.

1.1.2 相关函数

头文件:unistd.h

创建管道原型:int pipe(int filedes[2]);参数filedes返回两个文件描述符:filedes[0]用于读出数据,读取时必须关闭写入端,即close(filedes[1]);filedes[1]用于写入数据,写入时必须关闭读取端,即close(filedes[0]);。

1.2 命名管道

1.2.1 概念及相关知识

命名管道可以使用在两个互不相干的进程间通信,有名管道可以通过路径名指出,并在文件系统中显示出来。 在Linux系统中专门设置了一种特殊的系统文件-管道文件——FIFO的文件形式存在于文件系统中,这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就可以通过FIFO进行彼此间的通信。但在磁盘上只是一个节点,而文件的数据则存在于内存缓冲页面中,与普通管道一样。

1.2.2 相关函数

头文件:sys/types.h、sys/sta.h 函数原型:int mkfifo(const char *filename, mode_t mode);FIFO在文件系统中表现为一个文件,大部分的系统文件调用都可以在FIFO上面,如read、open、write、close、unlink、stat等,但seek等函数不能对FIFO调用。filename是有名管道的路径,包含了有名管道的名字,如:“/tmp/myfifo”。mode是对管道的读写权限,是个八进制数,如0777。 用open函数打开命名管道时要注意亮点:

  1. 不能以O_RDWR模式打开命名管道FIFO文件,否则其行为是未定义的管道是单向的,不能同时读写;
  2. 传递给open调用的是FIFO的路径名,而不是正常的文件 打开FIFO文件通常有四种方式: 只读、阻塞模式:open(pathname, O_RDONLY); 只读、非阻塞模式:open(pathname, O_RDONLY | O_NONBLOCK); 只写、阻塞模式:open(pathname, O_WRONLY); 只写、非阻塞模式:open(pathname, O_WRONLY | O_NONBLOCK);

2 信号量(semaphore)

信号量是用来解决进程/线程之间的同步互斥问题的一种通信机制,它表示代表某一类资源。

2.1 无名信号量

无名信号量只能存在于内存中,要求使用信号量的进程必须能访问信号量所在的这一块内存,所以无名信号量只能应用在同一进程间的线程或者共享内存间的进程。

2.2 有名信号量

2.2.1 概念和相关知识

用于进程(线程)间同步互斥。

有名信号量必须指定一个相关联的文件名称,名称通常是文件系统中的某个文件,无名信号量不需要指定。有名信号量既可以用于线程间的同步,也可以用于进程间的同步;无名信号量通过shared参数来决定是进程间还是相关线程共享。

有名信号量随内核时间持续,一个进程创建一个信号量,另外的进程也可以通过该信号量的外部名(创建信号使用的文件名称)来访问它。进程结束后,信号量还存在,并且信号量的值也不会改动。

无名信号量的持续性却是不定的:如果无名信号量是由单个进程内的各个线程共享的,那么该信号量就是随进程持续的,当该进程终止时它也会消失。如果某个无名信号量是在不同进程间同步的,该信号量必须存放在共享内存区中,只要该共享内存区存在,该信号量就存在。

2.2.2 相关函数

2.2.2.1 创建信号量

头文件:sys/sem.h

函数原型:int semget(key_t key, int nsem, int oflag);

返回值:成功时返回信号量集的IPC标识符(一个正整数);失败时返回-1,errno被设定成以下某个值:

EACCES:没有访问该信号量集的权限

EEXIST:信号量集已经存在,无法创建

EINVAL:参数nsems的值小于0或者大于该信号量集的限制;或者是改key关联的信号量集已存在,并且nsems大于该信号量集的信号量数

ENOENT:信号量集不存在,同时没有使用IPC_CREAT

ENOMEM:没有足够的内存创建新的信号量集

ENOSPC:超出系统限制

参数:key:所创建或打开信号量集的键值,需要是惟一的非零整数;nsem:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效,一般为1.拖用于访问一个已存在的集合,那么就可以把该参数指定为0。oflag:调用函数的操作类型,有两个值:IPC_CREAT:若信号量已存在,返回该信号量标识符、IPC_EXCL:若信号量已存在,返回错误;也可用于设置信号量集的访问权限:SEM_R(read)和SEM_A(alter),两者通过or表示。

2.2.2.2 打开信号量

头文件:sys/sem.h

原型:int semop(int semid, struct sembuf *opsptr, size_t nops);

参数:semid:信号量标识符;opsptr:指向一个信号量操作数组,信号量操作由sembuf结构表示:

struct sembuf{

short sem_num;//除非使用一组信号量,否则它为0

short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,一个是 1

short sem_flg;//说明函数semop的行为。通常为SEM_UNDO,使操作系统跟踪信号,并在 //进程没有释放该信号量而终止时,操作系统自动释放该进程持有的信号量。

};

nops:规定opsptr数组中元素的个数

sem_op>0:进程释放占用的资源数,该值加到信号量的值上(V操作)

sem_op<0:需要获取该信号量的资源数,信号量值减去该值得绝对值(P操作)

sem_op=0:调用进程希望等待到该信号量值变为0

如果信号量值小于sem_op的绝对值(资源不能满足要求),则:指定IPC_NOWAIT时semop()出错返回EAGAIN,未指定IPC_NOWAIT时信号量的semncnt值加1(调用进程将进入休眠状态),然后调用进程被挂起直至:此信号量变成大于或等于sem_op的绝对值、从系统中删除了此信号量,返回EIDRM、进程捕捉到一个信号,并从信号处理程序返回EINTR

2.2.2.3 信号量操作

头文件:sys/sem.h

函数原型:int semctl(int semid, int semnum, int cmd, [union semun sem_union]);

参数:semnum:指定信号集中的哪个信号(操作对象);

cmd:指定将执行的命令,包括:

IPC_STAT:读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中

IPC_SET:设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数

IPC_RMID:删除不再使用的信号量

GETALL:用于读取信号量集中的所有信号量的值

GETNCNT:返回正在等待资源的进程数目

GETPID:返回最后一个执行semop操作的进程的PID

GETVAL:返回信号量集中的一个单个的信号量的值

GETZCNT:返回在等待完全空闲的资源的进程数目

SETALL:设置信号量集中的所有的信号量的值

SETVAL:设置信号量集中的一个单独的信号量的值

sem_union:可选项,取决于参数cmd,其结构如下:

union semun{

int val;//用于SETVAL,信号量的初始值

struct semid_ds *buf;//用于IPC_STAT和IPC_SET的缓冲区

unsigned short *array;//用于GETALL和SETALL的数组

};

返回值:成功时返回一个正数,失败时返回-1,同时设置errno为以下值之一:

EACCESS:权限不够

EFAULT:arg指向的地址无效

EIDRM:信号量集已经删除

EINVAL:信号量集不存在,或者semid无效

EPERM:EUID没有cmd的权利

ERANGE:信号量值超出范围

3 消息队列(message queue)

消息队列是由内核管理的内部链表,用于进程之间的传递信息。它克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

消息队列是通过IPC标识符来区别的,不同的消息队列之间是相互独立的链表。有足够权限的进程可以顺序地发送消息到消息队列中,被赋予读权限的进程可以读走消息队列中的消息。消息队列进行通信的进程可以是不相关的进程。

3.1 相关函数

3.1.1 创建消息队列

头文件:sys/types.h、sys/ipc.h、sys/msg.h

函数原型:int msgget(key_t key, int msgflg);

参数:key:命名消息队列的键,一般用ftok函数获取;msgflg:消息队列的访问权限,可以与以下键或操作:IPC_CREAT:不存在则创建,存在则返回已有的qid;

返回值:成功时返回以key命名的消息队列的标识符(非零正整数),失败时返回-1.

3.1.2 发送消息

头文件:sys/types.h、sys/ipc.h、sys/msg.h 函数原型:int msgsnd(int msgid, const void* msgp, size_t magsz, int msgflg); 参数:msgid:由msgget函数返回的消息队列标识符;msgp:将发往消息队列的消息结构体指针,结构为: struct msgbuf{ long type;//消息类型,由用户自定义 消息数据 //发送的消息(长度、类型可以自行指定),如char mtext[1024]; }; msgsz:消息长度,是消息结构体中待传递数据的大小(不是整个结构体的大小) msgflg:IPC_NOWAIT:消息队列满时返回-1;0:消息队列满时阻塞 返回值:成功时消息数据的一份副本被放到消息队列中,并返回0;失败时返回-1.

3.1.3 接收消息

头文件:sys/types.h、sys/ipc.h、sys/msg.h 函数原型:ssize_t msgrcv(int qid, void *msgp, size_t msgsz, long msgtype, int msgflg); 参数:msgid、msgp、magsz、msgflg的作用同函数msgsnd;msgtype:可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个消息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。 返回值:成功时返回放到接收缓存区中的字节数,消息被复制到由msgp指向的用户分配的缓存区中,然后删除消息队列中的对应消息;失败时返回-1。

3.1.4 控制消息队列

头文件:sys/types.h、sys/ipc.h、sys/msg.h 函数原型:int msgctl(int msgid, int cmd, struct msgid_ds *buf); 参数:msgid:由msgget函数返回的消息队列标识符;cmd:将要采取的动作,它可以取3个值之一: IPC_STAT:用来获取消息队列的信息,并存储在buf指向的msg_ds结构 IPC_SET:用来设置消息队列的属性,要设置的属性存储在buf指向的msggid_ds结构中 IPC_RMID:删除msqid标识的消息队列 buf:指向msgid_ds权限结构,它至少包括以下成员: struct msgid_ds{ uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; …… };

4 信号(signal)

信号用于通知接收进程某个事件已经发生,除了用于进程间通信外,还可以发送信号给进程本身。 信号由硬件产生,如从键盘输入Ctrl C可以终止进程;由其他进程发送,如shell下用命令kill -信号标号PID可以向制定进程发送信号;进程异常时会发送信号。 信号是由操作系统来处理的,说明信号的处理在内核态。信号不一定会立即被处理,此时会存储在信号的信号表中。 信号处理的三种方式:忽略;默认处理方式:操作系统设定的默认处理方式;自定义信号处理方式:可自定义信号处理函数。

4.1 相关函数

4.1.1 signal函数(自定义信号处理)

头文件:signal.h 函数原型:void(*signal(int sig, void( *func)(int) ))(int); 功能:用于处理指定的喜好,主要通过忽略和恢复其默认行为来工作 参数:sig:信号值;func:信号处理函数指针,参数为信号值。 信号处理函数的原型必须为void func(int),或者是下面的特殊值: SIG_IGN:忽略信号的处理 SIG_DFL:恢复信号的默认处理

4.1.2 常见信号

SIGHUP:在用户终端结束时发出。通常是在终端的控制进程结束时,通知同一会话期内的各个作业,这时他们与控制终端不再关联。比如,登录Linux时,系统会自动分配给登录用户一个控制终端,在这个终端运行的所有程序,包括前台和后台进程组,一般都属于同一个会话。当用户退出时,所有进程组都将收到该信号,这个信号的默认操作是终止进程。此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 SIGINT:程序终止信号。当用户按下Ctrl C时通知前台进程组终止进程。 SIGQUIT:Ctrl 控制,进程接收到该信号退出时会产生core文件,类似于程序错误信号。 SIGILL:执行了非法命令。通常是因为可执行文件本身出现错误,或者数据段,堆栈溢出时也有可能产生这个信号。 SIGABRT:调用abort函数产生,将会使程序非正常结束。 SIGBUS:非法地址。包括内存地址对齐出错。比如访问一个4字节长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对核发地址的非法访问触发。 SIGFPE:发生致命的算术运算错误。 SIGKILL:用来立即结束程序的运行。 SIGUSR1:留给用户使用,用户可以自定义。 SIGSEGV:访问未分配给用户的内存区。或操作没有权限的区域。 SIGUSR2:留给用户使用,用户可以自定义。 SIGPIPE:管道破裂信号。当对一个进程已经运行结束的管道执行写操作时产生。 SIGALRM:时钟定时信号。由alarm函数设定的时间终止时产生。 SIGTERM:程序结束信号。shell使用kill产生该信号,当结束不了该进程,尝试使用SIGKILL信号。 SIGSTKFLT:堆栈错误。 SIGCHLD:子进程结束,父进程会收到。如果子进程结束时父进程不等待或者不处理该信号,子进程就会变成僵尸进程。 SIGCONT:让一个停止的进程继续执行。 SIGSTOP:停止进程执行。暂停执行。 SIGTSTP:停止运行,可以被忽略Ctrl Z。 SIGTTIN:当后台进程需要从终端接收数据时,所有进程会收到该信号,暂停执行。 SIGTTOU:与SIGTTIN类似,但在写终端时产生。 SIGURG:套接字上出现紧急情况时产生。 SIGXCPU:超过CPU时间资源限制时产生的信号。 SIGXFSZ:当进程企图扩大文件以至于超过文件大小资源限制时产生。 SIGVTALRM:虚拟使用信号。计算的是进程占用CPU调用的时间。 SUGPROF:包括进程使用CPU时间以及系统调用的时间。 SIGWINCH:窗口大小改变时。 SIGIO:文件描述符准备就绪,表示可以进行输入输出操作。 SIGPWR:电源失效信号。 SIGSYS:非法的系统调用。

4.1.3 sigaction函数

函数原型:int sigaction(int sig, const struct sigaction *act, struct sigaction oact); 功能:设置与信号sig关联的动作 参数:sig:信号值;act:指定信号的动作;oact:保存原信号的动作。 sigaction函数有阻塞的功能,默认情况下,在信号处理函数未完成之前,发生的新的SIGINT信号将被阻塞,同时对后续来的SIGINT信号进行排队合并处理。 sigaction结构体: struct sigaction{ void()(int)sa_handle;//处理函数指针,相当于signal函数的func参数 sigset_t sa_mask;//被屏蔽的信号,可以消除信号间的竞态 int sa_flags;//处理函数执行完后,信号处理方式修改。如SA_RESETHAND,将信号处理方式重//置为SIG_DFL } 信号屏蔽集sa_mask可以通过函数sigemptyset/sigaddset等来清空和增加需要屏蔽的信号。 sa_flags:0:默认行为;SA_NODEFER:不进行当前处理信号到阻塞;SA_RESETHAND:处理完当前新好后,将信号处理函数设置为SIG_DFL行为。

4.1.4 信号的阻塞

阻塞是阻止进程收到该信号,此时信号处于未决状态,放入进程的未决信号表中,当解除对该信号的阻塞时,未决信号会被进程接收。 阻塞信号原型:int sigprocmask(int how, const sigset_t *set, sigset_t *oset); how:设置block阻塞表的方式:SIG_BLOCK:将信号集添加到block表中;SIG_UNBLOCK:将信号集从block表中删除;SIG_SETMASK:将信号集设置为block表。 set:要设置的集合。 oset:设置前保存之前的block表信息。 获取未决信号原型:int sigpending(sigset_t *set); set:存储获得的当前进程的pending未决表中的信号集

4.1.5 信号的发送kill函数

函数原型:int kill(pid_t pid, int sig); 功能:发送信号给进程或进程组,可以是本身或其他进程。 参数:pid:>:发送给进程ID;0:发送给所有和当前进程在同一个进程组的进程;-1:发送给所有的进程表中的进程(进程号最大的除外);<-1:发送给进程组号为-PID的每一个进程。sig:信号值。 返回值:成功时返回0;失败时返回-1;失败原因通常有三大原因:给定的信号无效(errno=EINVAL)、发送权限不够(errno=EPERM)、目标进程不存在(errno=ESRCH)。

4.1.6 信号的发送raise函数

函数原型:int raise(int sig); 参数:sig:信号值 返回值:成功时返回0;失败时返回-1。

4.1.7 信号的发送abort函数

函数原型:void abort(void); 功能:发送SIGABRT信号,让进程异常终止,发生转储(core)。

4.1.8 信号的发送pause函数

函数原型:int pause(void); 返回值:成功时返回0;失败时返回-1,同时把errno设置为EINTR。 pause()函数用于将调用进程挂起直至捕捉到信号为止,这个函数可以用于判断信号是否已到达。

4.1.9 信号的发送alarm函数

函数原型:int alarm(unsigned int seconds); 功能:发送SIGALRM闹钟信号。 参数:seconds:系统经过seconds秒后向进程发送SIGALRM信号。 返回值:成功时,如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟的剩余时间,失败时返回-1。 可以在进程中设置一个定时器,当定时器指定的时间到时,它就向进程发送SIGALARM信号。一个进程只能有一个闹钟时间,如果在调用alarm()之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。

5 共享内存(shared memory)

内存共享就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。 共享内存是最快的IPC方式,往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。

5.1 相关函数

5.1.1 创建/获取共享内存shmget函数

头文件:sys/ipc.h、sys/shm.h 函数原型:int shmget(key_t key, size_t, int shmflg); 参数:key:共享内存段的名字,通常用ftok()函数获取;size:以字节为单位的共享内存大小。内核以页为单位分配内存,但最后一页的剩余部分内存不可用;shmflg:九个比特的权限标志(其作用与文件mode模式标志相同),并与IPC_CREAT或时创建共享内存段。 返回值:成功时返回非负整数,即该共享内存段的标识码,失败时返回-1。

5.1.2 将共享内存连接到进程地址空间shmat函数

函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg); 参数:shmid:由shmget返回的共享内存标识;shmaddr:指定共享内存连接到当前进程中的地址位置:shmaddr=NULL:核心自动选择一个地址、shmaddr<>NULL且shmflg=SHM_RND:以shmaddr为连接地址、shmaddr<>NULL且shmflg=SHM_RND:连接的地址会自动向下调整为SHMLBA的整数倍,公式:shmaddr-(shmaddr%SHMLBA);shmflg:它有两个可能的取值,用来控制共享内存连接的地址:SHM_RND:以shmaddr为连接地址、SHM_RDONLY:表示连接操作用来只读共享内存。 返回值:成功时返回指向内存第一个节的指针,失败时返回-1。

5.1.3 将共享内存段与当前进程脱离shmdt函数

函数原型:int shmdt(const coid *shmaddr); 功能:将共享内存从当前进程中分离。 参数:shmaddr:shmat所返回的指针。 返回值:成功时返回0;失败时返回-1. 共享内存分离并未删除它,只是是的该共享内存对当前进程不再可用。

5.1.4 共享内存控制shmctl函数

函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf); 参数:shmid:由shmget返回的共享内存标识码;cmd:将要采取的动作,有三个可取值:IPC_STAT:把shmid_ds结构中的数据这是为共享内存的当前关联值、IPC_SET:如果有足够的权限,把共享内存的当前值设置为shmid_ds数据结构中给出的值;IPC_RMID:删除共享内存段;buf:用于保存共享内存模式状态和访问权限,至少包含以下成员: struct shmid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; } 返回值:成功时返回0;失败时返回-1。

6 套接字(socket)

套接字是一种进程间通信机制,可用于不同机器间的进程通信。套接字起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

6.1 相关函数

头文件:sys/types.h、sys/socket.h

6.1.1 socket函数

函数原型:int socket(int domain, int type, int protocol); 参数:domain:程序采用的通讯协族:AF_UNIX:只用于单一的Unix系统进程间的通信、AF_INET:用于Internet通信;type:采用的通讯协议:SOCK_STREAM:用TCP协议、SOCK_DGRAM:用UDP协议;protocol:由于指定了type,此值一般为0。 返回值:成功时返回Socket描述符;失败时返回-1,可用errno查看出错的详细情况。 示例: TCP:sockfd = socket(AF_INET, SOCK_STREAM, 0); UDP:sockfd = socket(AF_INET, SOCK_DGRAM, 0);

6.1.2 bind函数

函数原型:int bind(int sockfd, struct sockaddr* servaddr, int addrlen); 作用:用于Server程序,绑定被侦听的端口。 参数:sockfd:由socket调用返回的文件描述符;servaddr:出于兼容性,一般使用sockaddr_in结构;addrlen:servaddr结构的长度。 返回值:成功时返回0;失败时返回-1. 在Linux系统中,1024以下的端口只有拥有root权限的程序才能绑定。

6.1.3 connect函数

函数原型:int connect(int sockfd, struct sockaddr* sercaddr, int addrlen); 作用:用于Client程序,连接到某个Server。 参数:sockfd:socket返回的文件描述符;servaddr:被连接的服务器端地址和端口信息,出于兼容性,一般使用sockaddr_in结构;addrlen:servaddr的长度。 返回值:成功时返回0;失败时返回-1,相应地设定全局变量errno。

6.1.4 listen函数

函数原型:int listen(int sockfd, int backlog); 作用:用于Server程序,真挺bind绑定的套接字。 参数:sockfd:被bind的文件描述符(socket()建立的);backlog:设置Server端请求队列的最大长度。 返回值:成功时返回0;失败时返回-1。

6.1.5 accept函数

函数原型:int accept(int sockfd, struct sockaddr* addr, int *addrlen); 作用:Server用它响应连接请求,建立与Client连接。 参数:sockfd:listen后的文件描述符(socket()建立的);addr:返回Client的IP、端口等信息,确切格式由套接字的地址类别(如TCP或UDP)决定;若addr为NULL,则addrlen应置为NULL;addrlen:返回真是的addr所指向的结构的大小,只要传递指针就可以,但必须先初始化为addr所指向结构的大小。注意:addr通常是指向局部数据结构sockaddr_in的指针。addrlen是局部变量,通常设置为sizeof(struct sockaddr_in)。 返回值:成功时Server用于与Client进行数据传输的文件描述符;失败时返回-1,相应地设定全局变量errno。 accept是阻塞函数,服务器端会一直阻塞到有一个客户程序发出了连接。

6.1.6 recv函数

函数原型:sszie_t recv(int sockfd, void *buf, size_t nbutes, int flags); 作用:用于TCP协议中接收信息。 参数:sockfd:接收端套接字描述符;buf:指向容纳接收信息的缓冲区的指针;nbytes:buf缓冲区的大小;flags:接收标志,一般置为0或: MSG_DONTWAIT:仅本操作非阻塞 MSG_OOB:发送或接受带外数据 MSG_PEEK:窥看外来信息 MSG_WAITALL:等待所有数据 返回值:成功时返回实际接收的字节数;失败时返回-1,相应地设定全部变量errno;为0:时表示对端已经关闭。 recv缺省是阻塞函数,知道接收到信息或出错。

6.1.7 recvfrom函数

函数原型:ssize_t recvfrom(int sockfd, void *buf, size_t len,int flags, struct sockaddr *from, socklen_t *fromlen); 作用:用于UDP协议中接收信息。 参数:sockfd:socket描述符;buf:指向容纳接收UDP数据报的缓冲区的指针;len:buf缓冲区的大小;flags:接收标志,一般为0;from:指明数据的来源;fromlen:传入函数之前初始化为from的大小,返回之后存放from实际大小。 返回值:成功时返回实际接受的字节数;失败时返回-1,错误原因存于errno中;为0时表示对端已经关闭。 recvfrom是阻塞函数,直到接收到信息或出错。

6.1.8 send函数

函数原型:ssize_t send(int sockfd, const void *buf,size_t bnytes, int flags); 作用:用于TCP协议中发送消息。 参数:sockfd:指定发送端套接字描述符;buf:存放要实际发送数据的缓冲区;nbytes:实际要发送的数据的字节数;flags:一般设置为0或: MSG_DONTROUTE:绕过路由表查找 MSG_DONTWAIT:仅本操作非阻塞 MSG_OOB:发送或接收带外数据 返回值:成功时返回已发送的字节数;失败时返回-1,相应地设定全局变量errno。 send缺省是阻塞函数,知道发送完毕或出错。

6.1.9 sendto函数

函数原型:int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); 作用:用于UDP协议中发送信息; 参数:sock:将要从其发送数据的套接字;buf:指向将要发送数据的缓冲区;len:数据缓冲区的长度;flags:一般是0;to:指明数据的目的地;tolen:to内存区的长度。 返回值:成功时返回实际传送出去的字符数;失败时返回-1,错误原因存于errno中。 sendto缺省是阻塞函数,直到发送完毕或出错。

6.1.10 close函数

函数原型:int close(int sockfd); 作用:用于TCP,关闭特定的socket连接。 返回值:成功时返回0;失败时返回-1,并设置错误码errno: EBADF:sockfd描述符无效 EINTR:close函数被信号中断 EIO:IO错误 close一个TCP socket的缺省行为是把该socket标记为已关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用。close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

0 人点赞