socket简述

1.简述

1.网络中标识主机和地址:ip地址唯一标识主机,协议+端口唯一标识主机的进程
2.三元组(ip地址、协议、端口)唯一标识网络中的进程,网络中的进程通过socket实现。
3.socket是一种文件:对其打开->读/写->关闭

2.socket的函数

1.socket();
int socket(int domain,int type,int protocol);//对应于普通文件的打开操作,普通文件返回一个文件的描述符,socket()返回一个socket的描述符,唯一标识一个socket,后续的读写操作都把它作为参数传进去
参数:

  • domain:协议簇,常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
  • type:常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
  • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
    注意:type不能和protocol任意组合,如SOCK_STREAM不能和IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。

2.bind();

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

参数:

  • sockfd:socket描述符,通过socket()创建
  • addr:一个结构体指针,指明绑定给socket的协议地址,协议簇不同内容不同,比如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 */
};
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域对应的是:
#define UNIX_PATH_MAX    108

struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */ 
    char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};
  • addrlen:对应的是地址的长度。

注意:服务端需要bind,客户端不需要。服务端在listen()之前bind(),客户端在connect()之前不需要bind(),系统自动给客户端分配一个。

3.listen()、connect()
服务器:调用socket()、bind()之后就会调用listen()来监听socket
客户端:调用connect()发出连接请求

int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数,如果超过这个最大连接个数,就拒绝连接。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

connect()第一个参数是客户端的socket描述字,第二参数是服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

4.accept()
服务端:socket()->bind()->listen()->accept()
客户端:socket()->connect()
int accepr(int sockfd,struct sockaddr* addr,sockelen_t *addlen)

  • sockfd:服务端的套结字
  • addr:客户端的协议地址
  • addrlen:协议长度

如果accept成功,其返回中是一个套结字,代表和客户端的TCP连接,当服务器完成客户的服务,关闭该套结字。
服务器还可以使用I/O多路复用的方式,来等待一个请求的到来。
5.read()、write()
网络I/O的操作
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvform()/sendto()

		#include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);
       ssize_t write(int fd, const void *buf, size_t count);

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

       ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//      send成功返回代表把数据无错误地发送到了网络驱动程序上
//		对于支持报文边界的协议,如果尝试发送单个报文的长度超过协议所支持的最大长度,send就会失败,errno设为EMSGSIZE
//		对于字节流协议,send会阻塞直到整个数据传输完成。send和sendto很类似,区别是sendto可以在无连接的套接字上指定一个目标地址。
       ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//		recv和read类似,但是recv可以指定如何接受数据,flags标志位可以指定(MSG_DONTWAIT,非阻塞模式);(MSG_PEEK,返回数据包内容,而不真正取走数据包)...
//		对于SOCK_STREAM套接字,接受的数据可以比预期的少。MSG_WAITALL标志会阻止这种行为,直到所请求的数据全部返回,recv函数才会返回。
//		如果发送者调用shutdown来结束传输,或者网络协议支持按默认的顺序关闭并且发送端已经关闭,那么当所有的数据接受完毕后,recv会返回0

       ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
//		对于无连接的套接字,需要先连接,在用send发送。sendto函数中有目的地址,可以发送无连接的报文。
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
//		如果有兴趣定位发送者,可以使用recvfrom来得到数据发送者的源地址
//		recvfrom通常用于无连接的套接字,否则recvfrom等同于recv

       ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
//		带有msghdr结构,和writev(聚集写)类似,将多个缓冲区写到通道中。
       ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
//		将数据送入多个缓冲区,类似于readv

6.close();
close(int fd);

#include <unistd.h>
int close(int fd);
库文件
#include<netinet/in.h>
IPPROTO_TCP
sockaddr_in
INADDR_ANY
htonl
htons
#include<sys/types.h>
#include<sys/socket.h>

3.专有名词

带外数据:TCP称其为紧急数据,是一些通信协议栈所支持的可选功能,具有高优先级传输。TCP支持带外数据,但是UDP不支持。紧急数据被接受时,会发送SIGURG信号。
进程的基本属性:进程ID,父进程ID,进程组ID,会话和控制终端

  • 进程ID:每一个进程都有一个非负整数表示的唯一进程ID(PID),进程ID(PID)是无法在用户层改动的。在linux系统中,PID为0的进程一般是调度进程,经常被成为交换进程。
    idle进程:由系统自动创建的,运行在内核态,完成加载系统后,演变为进程调度、交换。
    init进程:是由idle进程通过kernel_thread创建,完成系统的初始化,是系统中所有其他用户进程的祖先进程。linux中所有的进程都是由init进程创建的并运行的。首先在linxu内核中启动,然后在用户空间中启动init进程,在启动其他系统进程,在系统启动完成后,init变为守护进程监视系统其他进程。
    kthread进程:由idle进程通过kernel_thread进创建,并始终运行在内核空间,负责所有内核线程的调度和管理。
    **守护进程:**守护进程是脱离中断,并在后台运行的进程,一般守护进程的生命周期是系统开始到系统结束。守护进程的创建步骤:①创建子进程,父进程退出(孤儿进程一般是由1号进程收养);②创建会话setsid();;③改变当前目录为根目录chdir("/");;④设置文件掩码umask(0);
    文件权限 rwx 421,可读,可写,可执行
  • 父进程ID:除了0号进程,其他进程都有一个进程创建,这个进程就叫做父进程,这个ID就是父进程ID,叫做PPID。
  • 进程组ID:是一个进程或多个进程的集合。 进程组的作用在于方便对进程的管理,如果一个任务需要创建100个进程,在终止的时候,如果没有进程组,需要一个个的去终止。有了进程组,就可以将这100个进程设为一个进程组,他们共有一个组号,并且选取辈分最高的那个进程作为组长,组长的进程ID就是这个进程组的ID。那么就可以通过杀死整个进程组,来关闭这100个进程并且是严格有序的。
setpgid(pid_t pidm,,pid_t pgid);//修改进程组ID的接口
  • 会话:会话是一个或多个进程组的集合,包含了登录用户的所有活动。
    • 一次会话就是打开一个终端,用户的登录shell就是会话的首进程。一个会话可以包含多个进程组,但是只能有一个前台进程组,每个进程都有一个会话首领(leader),即创建会话的进程。当前进程不是进程组组长时,可以调用setsid创建一个新的会话,这个进程就成为新会话的leader。
    • 前台进程和后台进程: 1.对于执行很长时间的进程,不用傻傻的等待命令运行完毕才执行下一个命令,可以在命令的结尾添加&符号,将命令放入后台执行,这样,该命令对应的进程组就是后台进程组。2.在任意时刻,shell只能由一个前台进程组,只有前台进程组才会读取终端的输入,在终端信号输入终端字符,对应的信号指挥发送给前台进程组。
    • 为什么会话的创建者不能是进程组的组长: 如果进程组组长创建会话,这个进程就会迁移到新的会话中,进程组的其他成员仍然在老会话中,就会出现一个进程组的进程分属不同的会话中,这就破坏了进程组和会话的严格的层次关系。
  • 作业: shell分前后台控制的不是进程,而是作业或者进程组,作业可以由多个进程组组成。shell可以运行一个前台作业和多个后台作业,这成为作业控制。作业和进程组的区别:如果作业中某个进程又创建了子进程,那么这个子进程不属于作业。

程序和进程的区别: 程序是存储在磁盘上的可执行机器指令和数据的静态实体。进程是被操作系统从磁盘加载到内存上的、动态的、可运行的指令与数据的集合,实在运行的动态实体。

临界区资源: 各进程采用互斥的方式,访问的资源叫做临界区资源。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值