Socket 编程 参考.pdf

上传人:qwe****56 文档编号:70014516 上传时间:2023-01-14 格式:PDF 页数:29 大小:220KB
返回 下载 相关 举报
Socket 编程 参考.pdf_第1页
第1页 / 共29页
Socket 编程 参考.pdf_第2页
第2页 / 共29页
点击查看更多>>
资源描述

《Socket 编程 参考.pdf》由会员分享,可在线阅读,更多相关《Socket 编程 参考.pdf(29页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、Socket 编程 Socket 编程 参考 UNP 第一卷 chinaunix 论坛 一、基本知识 一、基本知识 主机字节序和网络字节序 主机字节序和网络字节序 主机字节序即内存中存储字节的方法有:1 Little endian:将低序字节存储在起始地址 2 Big endian:将高序字节存储在起始地址 网络字序表示网络协议在处理多字节时的顺序,一律为 big endian 主机字节序和网络字节序转换的函数:#include uint16_t htons(uint16_t)uint32_t htonsl(uint32_t)/转换为网络字节序 uint16_t ntohs(uint16_t)

2、uint32_t ntohl(uint32_t)/转换为主机字节序 缓冲区 缓冲区 每个 TCP SOCKET 有一个发送缓冲区和一个接收缓冲区,TCP 具有流量控制,所以接收缓冲区的大小就是通知另一端的窗口的大小,对方不会发大于该窗口大小的数据;而 UDP SOCKET 只有一个接收缓冲区无流量控制,当接收的数据报溢出时就会被丢弃 通信域(地址族)通信域(地址族)套接字存在于特定的通信域(即地址族)中,只有隶属于同一地址族的套接字才能建立对话。Linux 支持 AF_INET(IPv4 协议)、AF_INET6(IPv6 协议)和 AF_LOCAL(Unix 域协议)。套接口(socket)

3、网络地址+端口号。,要建立一个套接口必须调用 socket 函数,套接口有三种类型,即字节流套接口(SOCK_STREAM),数据报套接口(SOCK_DGRAM)和原始套接口(SOCK_RAW)。定义一个连接的一个端点的两元组,即 IP 地址和端口号,称为一个套接口。在网络连接中,两个端点所组成的四元组(即本地 IP、本地 PORT、远程 IP 和远程 PORT)称为 socket pair,该四元组唯一的标识了一个网络连接。该情况可通过 netstat 验证。二、socket 地址结构 1二、socket 地址结构 1 IPv4 的 Socket 地址结构(定长)IPv4 的 Socket

4、地址结构(定长)Struct in_addr In_addr_t s_addr;/32 位 IP 地址,网络字节序 Struct sockaddr_in Uint8_t sin_len;/IPv4 为固定的 16 字节长度 Sa_family_t sin_family;/地址簇类型,为 AF_INET In_port_t sin_port;/16 位端口号,网络字节序 Struct in_addr sin_addr;/32 位 IP 地址 Char sin_zero8;/未用 22 IPv6 的 socket 地址结构(定长)IPv6 的 socket 地址结构(定长)struct in6_a

5、ddr uint8_t s6_addr16;/128 位 IP 地址,网络字节序 struct sockaddr_in6 uint8_t sin6_len;/IPv6 为固定的 24 字节长度 sa_family_t sin6_family;/地址簇类型,为 AF_INET6 in_port_t sin6_port;/16 位端口号,网络字节序 uint32_t sin6_flowinfo;/32 位流标签 struct in6_addr sin6_addr;/128 位 IP 地址 3 3 UNIX 域 socket 地址结构(变长)UNIX 域 socket 地址结构(变长)Struct

6、sockaddr_un,地址簇类型为 AF_LOCAL 4 4 数据链路 socket 地址结构(变长)数据链路 socket 地址结构(变长)struct sockaddr_dl,地址簇类型为 AF_LINK 5 5 通用的 socket 地址结构 通用的 socket 地址结构 struct sockaddr uint8_t sa_len;sa_family_t sa_family;char sa_data14;三、C/S 网络编程 三、C/S 网络编程 初始化 sock 连接符:int socket(int domain,int type,int protocol);函数返回 socke

7、t 描述符,返回-1 表示出错 domain 参数只能取 AF_INET,protocol 参数一般取 0 应用示例:TCP 方式:sockfd=socket(AF_INET,SOCK_STREAM,0);UDP 方式:sockfd=socket(AF_INET,SOCK_DGRAM,0);绑定端口:int bind(int sockfd,struct sockaddr*sa,int addrlen);函数返回-1 表示出错,最常见的错误是该端口已经被其他程序绑定。需要注意的一点:在 Linux 系统中,1024 以下的端口只有拥有 root 权限的程序才能绑定。连接网络(用于 TCP 方式)

8、:int connect(int sockfd,struct sockaddr*servaddr,int addrlen);函数返回-1 表示出错,可能是连接超时或无法访问。返回 0 表示连接成功,可以通过 sockfd 传输数据了。监听端口(用于 TCP 方式):int listen(int sockfd,int queue_length);需要在此前调用 bind()函数将 sockfd 绑定到一个端口上,否则由系统指定一个随机的端口。接收队列:一个新的 Client 的连接请求先被放在接收队列中,直到 Server 程序调用 accept 函数接受连接请求。第二个参数 queue_len

9、gth,指的就是接收队列的长度 也就是在 Server 程序调用 accept 函数之前最大允许的连接请求数,多余的连接请求将被拒绝。响应连接请求(用于 TCP 方式):int accept(int sockfd,struct sockaddr*addr,int*addrlen);accept()函数将响应连接请求,建立连接并产生一个新的 socket 描述符来描述该连接,该连接用来与特定的 Client 交换信息。函数返回新的连接的 socket 描述符,错误返回-1 addr 将在函数调用后被填入连接对方的地址信息,如对方的 IP、端口等。addrlen 作为参数表示 addr 内存区的大

10、小,在函数返回后将被填入返回的 addr 结构的大小。accept 缺省是阻塞函数,阻塞直到有连接请求 应用示例:struct sockaddr_in their_addr;/*用于存储连接对方的地址信息*/int sin_size=sizeof(struct sockaddr_in);(依次调用 socket(),bind(),listen()等函数)new_fd=accept(sockfd,&their_addr,&sin_size);printf(”对方地址:%sn,inet_ntoa(their_addr.sin_addr);关闭 socket 连接:int close(int soc

11、kfd);关闭连接将中断对该 socket 的读写操作。关闭用于 listen()的 socket 描述符将禁止其他 Client 的连接请求。部分关闭 socket 连接:int shutdown(int sockfd,int how);Shutdown()函数可以单方面的中断连接,即禁止某个方向的信息传递。参数 how:0-禁止接收信息 1-禁止发送信息 2-接收和发送都被禁止,与 close()函数效果相同 socket 轮询选择:int select(int numfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,struct ti

12、meval*timeout);应用于多路同步 I/O 模式(将在同步工作模式中详细讲解)FD_ZERO(*set)清空 socket 集合 FD_SET(s,*set)将 s 加入 socket 集合 FD_CLR(s,*set)从 socket 集合去掉 s FD_ISSET(s,*set)判断 s 是否在 socket 集合中 常数 FD_SETSIZE:集合元素的最多个数 等待选择机制:int poll(struct pollfd*ufds,unsigned int nfds,int timeout);是 select 机制的一个变种,应用于多路同步 I/O 模式(将在同步工作模式中详细

13、讲解)ufds 是 pollfd 结构的数组,数组元素个数为 nfds。struct pollfd int fd;/*文件描述字*/short events;/*请求事件集合*/short revents;/*返回时间集合*/;接收/发送消息:TCP 方式:int send(int s,const void*buf,int len,int flags);int recv(int s,void*buf,int len,int flags);函数返回实际发送/接收的字节数,返回-1 表示出错,需要关闭此连接。函数缺省是阻塞函数,直到发送/接收完毕或出错 注意:如果 send 函数返回值与参数 le

14、n 不相等,则剩余的未发送信息需要再次发送 UDP 方式:int sendto(int s,const void*buf,int len,int flags,const struct sockaddr*to,int tolen);int recvfrom(int s,void*buf,int len,int flags,struct sockaddr*from,int*fromlen);与 TCP 方式的区别:需要指定发送/接收数据的对方(第五个参数 to/from)函数返回实际发送/接收的字节数,返回-1 表示出错。函数缺省是阻塞函数,直到发送/接收完毕或出错 注意:如果 send 函数返回

15、值与参数 len 不相等,则剩余的未发送信息需要再次发送 注意,网络字节流的读写不同于文件的读写,由于 socket 缓冲的因素,可能读写的字节数小于所指定的字节数。所以可以使用如下函数:ssize_t readn(int fd,void*buf,size_t n)ssize_t nleft;ssize_t nread;char*ptr;ptr=buf;nleft=n;while(nleft 0)if(nread=read(fd,ptr,nleft)0)if(nwrite=write(fd,ptr,left)=0)if(errno=EINTR)nwrite=0;else return(-1);

16、nleft-=nwrite;ptr+=nwrite;return(n);基于消息的方式:int sendmsg(int s,const struct msghdr*msg,int flags);int recvmsg(int s,struct msghdr*msg,int flags);标志位:上面这六个发送/接收函数均有一个参数 flags,用来指明数据发送/接收的标志,常用的标志主要有:MSG_PEEK 对数据接收函数有效,表示读出网络数据后不清除已读的数据 MSG_WAITALL 对数据接收函数有效,表示一直执行直到 buf 读满、socket 出错或者程序收到信号。MSG_DONTWA

17、IT 对数据发送函数有效,表示不阻塞等待数据发送完后返回,而是直接返回。(只对非阻塞 socket 有效)MSG_NOSIGNAL 对发送接收函数有效,表示在对方关闭连接后出错但不发送 SIGPIPE 信号给程序。MSG_OOB 对发送接收都有效,表示读/写带外数据(out-of-band data)IP 地址字符串和网络字节序的二进制 IP 地址相互转换的函数:IP 地址字符串和网络字节序的二进制 IP 地址相互转换的函数:#inlcude int inet_aton(const char*,struct in_addr*)成功1 失败0 通用地址函数int inet_pton(int,可以

18、是 AF_INET/AF_INET6,const char*,void*)成功1 格式错误0 失败0 in_addr_t inet_addr(const char*)返回 32 位网络字节序的 IP 地址,失败INADDR_NONE char*inet_ntoa(struct in_addr)返回 IP 地址字符串 const char*inet_ntop(int,const void*,char*,size_t )返回指向结果的指针 字节顺序转换 htons()-Host to Network Short htonl()-Host to Network Long ntohs()-Networ

19、k to Host Short ntohl()-Network to Host Long 连接过程是通过一系列状态表示的,这些状态有:LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT 和 CLOSED。CLOSED 表示没有连接,各个状态的意义如下:LISTEN-侦听来自远方 TCP 端口的连接请求;SYN-SENT-在发送连接请求后等待匹配的连接请求;SYN-RECEIVED-在收到和发送一个连接请求后等待对连接请求的确认;ESTABLISH

20、ED-代表一个打开的连接,数据可以传送给用户;FIN-WAIT-1-等待远程 TCP 的连接中断请求,或先前的连接中断请求的确认;FIN-WAIT-2-从远程 TCP 等待连接中断请求;CLOSE-WAIT-等待从本地用户发来的连接中断请求;CLOSING-等待远程 TCP 对连接中断的确认;LAST-ACK-等待原来发向远程 TCP 的连接中断请求的确认;TIME-WAIT-等待足够的时间以确保远程 TCP 接收到连接中断请求的确认;CLOSED-没有任何连接状态;Tcp 面向连接 如下图所示:Socket()Server(主动打开)Bind()Listen()Accept()Socket(

21、)Client(被动打开)Connect()Write()Read()Read()Write()Close()Read()Close()#include int socket(int,int,int protocol)非负整数表示socket描述字-成功-1-失败#include int connect(int socket描述 字 ,c o n s t s t r u c ts o c k a d d r *服 务 器 的SOCKET地址,socklen_t 服务器的SOCKET地址结构长度)0成功1失败#include int bind(int,const structsockaddr*,

22、socklen_t)0-成功1-失败若SOCKET地址中:IP地址为通配地址INADDR_ANY(0),或PORT为0,都表示为让内核选择#include int listen(int,int)成功-1-出错3进入未完成连接队列中,SYN_RCVD状态4转入已完成队列队列中,ESTABLISHED状态#include int accept(int,structsockaddr*,socklen_t*)非负描述字(已连接套接口)-成功-1-出错2SYN_SENT状态1CLOSED状态3ESTABLISHED状态4FIN_WAIT1状态5FIN_WAIT2状态6TIME_WAIT状态7CLOSED

23、状态TIMEOUT=2MSL(max segementlifetime 1-4分钟)1CLOSED状态2LISTEN状态5CLOSED_WAIT6LAST_ACK7CLOSED TIME_WAIT 状态 一个 tcp 协议的 socket 编程例子:Server Server/*主函数*/int listenfd,connfd;struct sockaddr_in servaddr,cliaddr;struct hostent*hp;struct servent*sp;struct in_addr*pptr;if(hp=gethostbyname(argv1)=NULL)/error if(s

24、p=getservbyname(argv2,“tcp”)=NULL)/error pptr=(struct in_addr*)hp-h_addr_list;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr);servaddr.sin_family=AF_INET;/servaddr.sin_addr.s_addr=htonl(INADDR_ANY);memcpy(&servaddr.sin_addr,*pptr,sizeof(struct in_addr);servaddr.sin_port=htons

25、(portnum);bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr);listen(listenfd,listenqueuenum);signal(SIGCHLD,sig_chld);for(;)len=sizeof(cliaddr);if(connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&len)0);return;client client sockfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servad

26、dr);bzero(&servaddr,sizeof(servaddr);servaddr.sin_familf=AF_INET;servaddr.sin_port=htons(SERV_PORT);inet_pton(AF_INET,SERV_IP_STRING,&servaddr.sin_addr);connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(servaddr);./process exit(0);终止网络连接的正常方法是调用 close(),但是有两个限制:1 将描述字的访问计数-1,到 0 时才激发 TCP 连接的终止序列(丢弃

27、接收缓冲区里的数据,发送发送缓冲区里的数据,如果描述字的访问计数为 0,在数据之后发出 FIN)2 终止了数据传输的两个方向,读和写 shutdown 可以关闭一半连接,而且在发完发送缓冲区里的数据后立即发出 FIN 序列 UDP 无连接 编程时,在 SERVER 端少了 accept()和 listen(),客户端少了 connect(),因为是无连接的,所以不用 close(),读写一般用 sendto()和 recvfrom()。如果 client 发送的数据被路由丢弃或者服务器的应答信息丢失,那么 client 将一直阻塞,直到应用设置的超时到达,UDP 需要应用来做接受确认、传输超时

28、或者重传的机制。一般的,UDP 服务属于迭代的,而 TCP 服务大多数是并发的。用 I/O 复用方式(select())实现(可以避免为每个客户端连接创建一个进程的开销):server server int clientFD_SETSIZE;fd_set allset,rset;maxfd=listenfd;maxi=-1;for(I=0;I FD_SETSIZE;i+)clienti=-1;FD_ZERO(&allset);FD_SET(listenfd,&allset);For(;)rset=allset;nready=select(maxfd+1,&rset,NULL,NULL,NULL

29、);if(FD_ISSET(listenfd,&rset)/新连接 clilen=sizeof(cliaddr);connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&clilen);for(i=0;I FD_SETSIZE;i+)if(clienti maxfd)Maxfd=connfd;If(I maxi)Maxi=I;If(-nready=0)Continue;for(I=0;I=maxi;i+)if(sockfd=clienti)0)continue;if(FD_ISSET(sockfd,&rset)if(n=read(sockfd,)=

30、0)/客户端已经关闭连接 close(sockfd);FD_CLR(sockfd,&allset);Clienti=-1;else /process if(-nready=0)break;用这种方法有一个问题:容易受 DDOS 攻击。如一个客户端发一个字节,就睡眠,该程序将阻塞在 read()上,无法再为其他合法的客户端服务。解决方法:1 非阻塞 I/O 2 为每个连接创建进程或线程 3 对 I/O 操作设置操时 四、常用函数 四、常用函数 函数中均使用通用地址结构,所以一般要将特定协议的地址转换成通用地址结构。1从进程到内核 bind connect sendto sendmsg 2从内核到

31、进程 Accept Recvfrom Recvmsg Getpeername Getsockname 3.解析器函数:ethostbyname gethostbyaddr getservbyname 端口号是以网络字节序返回的 getservbyport 参数 port 必须是网络字节序,所以要调用 htons(port num)4I/O 流和描述字 fdopen():将描述字(int)转换为 I/O 流(FILE*)fileno():将 I/O 流转换为描述字 注 意:虽 然 一 个 I/O 流 也 是 全 双 工 的,但 是 读 和 写 之 间 必 须 要 有 一 些 如fflush(),

32、fseek(),fsetpos(),rewind()函数。最好的办法是对一个描述字创建两个流,读和写分开。FILE*fin,*fout;Fin=fdopen(sockfd,“r);Fout=fdopen(sockfd,“w”);Fgets();Fputs();但是这种标准 I/O 库的编程必须注意当前的缓冲方式:完全缓冲:只有缓冲区满、fflush()或进程 exit()时才输出 I/O 行缓冲 不缓冲 五、僵尸进程 五、僵尸进程 Zombie进程:一个子进程终止,系统内核会发出 SIGCHLD 信号,如果程序中没有用 singal、sigaction 进行 SIG_IGN 处理,也没有用 w

33、ait、waitpid 进行等待,结束的子进程就会变为僵尸进程。僵尸进程产生的目的是保存子进程的信息,以便父进程在以后某个时刻需要取回 如果一个进程终止,但子进程有 Zombie 状态,这时他们的父进程将由 pid=1 的 init 进程接管,用 wait 来等待负责收回僵尸进程的资源。僵尸进程占用内核空间,六、I/O 模式 六、I/O 模式 5 个 I/O 模式:1 阻塞 I/O 2 非阻塞 I/O 设置该标志代码:int flags;if(flags=fcntl(fd,F_GETFL,0)0)/出错处理 flags|=O_NONBLOCK;if(fcntl(fd,F_SETFL,flags

34、)0)/出错处理 关闭该标志代码:flags&=O_NONBLOCK;非阻塞 connect 的典型应用:/设置 sockfd 为非阻塞,如上述代码 if(n=connect()0)if(errno!=EINPROCESS)/正常情况下,connect 连接有一定时间,应该返回EINPROCESS return(-1);if(n=0)/特殊情况,如 CLIENT 和 SERVER 在同台主机上,连接快速返回 goto done;FD_ZERO(&rset);FD_SET(sockfd&rset);West=rset;Struct timeval val;Val.tv_sec=;Val.tv_u

35、sec=0;If(n=select(sockfd+1,&rset,&west,NULL,&val)=0)/超时 Errno=ETIMEOUT;Close(sockfd);Return(-1);int error;if(FD_ISSET(sockfd,&rset)|FD_ISSET(sockfd,&west)len=sizeof(error);if(getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&error,&len)0)/检查 SOCKET上待处理的错误 return(-1);else /出错处理,表示在这段时间内没连接上 SERVER done:fcntl(so

36、ckfd,FD_SETFL,flags);/恢复为原来的模式 if(error)close(sockfd);errno=error;return(-1);return(0);3 I/O 复用 4 信号驱动 I/O(SIGIO)5 异步 I/O 前 4 个 I/O 模式都属于同步 I/O,因为它们都阻塞于 I/O 的操作(即 I/O 数据准备好时,从内核空间往用户空间拷贝数据)七、守护进程 七、守护进程 在后台运行并且与终端脱离联系的进程,只要系统不停止就一直运行着。有几种方式启动:1/etc/rcx.d 下的启动脚本 2Inetd 启动 3Cron 或者 at 启动 守护进程的输出信息一般通过

37、 SYSLOG 输出 函数示例:#include#define MAXFD 64 void daemon_init()int I;pid_t pid;if(pid=fork()!=0)exit(0);setsid():signal(SIGHUP,SIG_IGN):if(Pid=fork()!=0)exit(0):chdir(“/”);umask(0);for(i=0;iMAXFD;i+)close(i);openlog(logname,LOG_PID,facility);八、I/O 超时 八、I/O 超时 方法 1:alarm()例如:static void connect_alarm(int

38、 signo)return;signal(SIGALARM,connect_alarm);if(alarm(timeout_sec)!=0)/error if(connect(sockfd,(struct sockaddr*)servaddr,servlen)0)close(sockfd);if(errno=EINTR)errno=ETIMEDOUT;alarm(0);方法 2:select()例如:int readable_timeout(int fd,int sec)fd_set rset;struct timeval tv;FD_ZERO(&rset);FD_SET(fd,&rset):

39、Tv.tv_sec=sec;Tv.tv_usec=0;Return(select(fd+1,&rset,NULL,NULL,&tv);sendto(sockfd,);if(readable_timeout(sockfd,5)=0)/error else recvfrom(sockfd,);/可以读 方法 3:SO_RCVTIMEO 和 SO_SNDTIMEO 套接口选项 例如:struct timeval tv;tv.tv_sec=5;tv.tv_usec=0;setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv):while(fgets

40、(sendline)!=NULL)sendto(sockfd,);n=recvfrom(sockfd,);if(n0)if(errno=EWOULEBLOCK)fprintf(stderr,“socket,timeout”);continue;else /error;九、辅助数据的应用 可以运用于任何进程之间传递描述字的应用 九、辅助数据的应用 可以运用于任何进程之间传递描述字的应用 sendmsg 和 recvmsg 可以用来传送辅助数据(控制信息)。辅助数据由若干个辅助对象组成,每个辅助对象由一个 cmsghdr 结构开头。struct msghdr void *msg_name;/用于

41、UDP 协议,发送方可以存放目的地址,接收方可以存放发送地址 size_t msg_namelen;/同上 struct iovec*msg_iov;/输入输出缓冲区数据,两个成员iov_base 和 iov_len int msg_iovlen;void *msg_control;/辅助数据 size_t msg_controllen;/辅助数据大小 int msg_flags;/只对 recvmsg 有用;Struct cmsghdr Socklen_t cmsg_len;Int cmsg_level;/IPV4 是 IPPROTO_IP,UNIX 域是 SOL_SOCKET Int Cm

42、sg_type;/在 IPV4 中,IP_RECVDSTADDR 接受 UDP 数据报的目的地址 /IP_RECVIF 接受 UDP 数据报的接口索引 /UNIX 域中是 SCM_RIGHTS 传送描述字 /SCM_CREDS 传送用户凭证 /char cmsg_data;msghdr.msg_control 指向的辅助数据必须按 cmsghdr 结构对齐。利用 UNIX 域 SOCKET 方式:my_open(const char*pathname,int mode)int sockfd2;socketpair(AF_LOCAL,SOCK_STREAM,0,sockfd);/创建了一个流管道

43、 if(childpid=fork()=0)/子进程 close(socdfd0);snprintf(argsockfd,sizeof(argsocdfd),“%d”,sockfd1);snprintf(argmode,sizeof(mode),“%d”,mode);execl(“./openfile”,“openfile”,argsockfd,pathname,argmode,(char*)NULL);perror(“exec errorn”);close(sockfd1);waitpid(chidpid,&status,0);if(WIFEXITED(status)=0)perror(“c

44、hid process did not terminaten”);if(status=WEXITSTATUS(status)=0)/把终止状态转换为退出状态 0-255 read_fd(sockfd0,&c,1,&fd);else errno=status;fd=-1;close(sockdf0);return(fd);ssize_t read_fd(int fd,void*ptr,ssize_t nbytes,int*recvfd)struct msghdr msg;/辅助数据对象 struct iovec iov1;union struct cmsghdr unit;/这里定义辅助数据对象

45、的目的是为了让 msg_control 缓冲区和辅助数据单元对齐,所以不是简单地定义一个char control,而是定义一个union char controlCMSG_SPACE(sizeof(int);/辅助数据缓冲区 control_buf;struct cmsghdr*unitptr;int n;msg.msg_control=control_buf.control;/辅助数据缓冲区 msg.msg_controllen=sizeof(control_buf.control);/辅助数据大小 msg.msg_name=NULL;msg.msg_namelen=0;iov0.iov_b

46、ase=ptr;iov0.iov_len=nbytes;msg.msg_iov=iov;msg.msg_iovlen=1;if(n=recvmsg(fd,&msg,0)cmsg_len=CMSG_LEN(sizeof(int)/cmsg_len 应该=CMSG_LEN 宏得出的结果 if(unitptr-cmsg_level!=SOL_SOCKET)/UNIX DOMAIN 用 SOL-SOCKET /error if(unitptr-cmsg_type!=SCM_RIGHTS)/error *recvd=*(int*)CMSG_DATA(unitptr);/获得该辅助对象的数据 else *

47、recvd=-1;return(n);子进程写程序摘录:msg.msg_control=control_buf.control;msg.msg_controllen=sizeof(control_buf.control);unitprt=CMSG_FIRSTHDR(&msg);unitptr-cmsg_len=CMSG_LEN(sizeof(int);unitptr-cmsg_level=SOL_SOCKET;unitptr-cmsg_level=SCM_RIGHTS;*(int*)CMSG_DATA(unitptr)=sendfd;/CMSG_DATA()返回与 cmsghdr 相关联的数据

48、的第一个字节的指针 msg.msg_name=NULL;msg.msg_namelen=0;iov0.iov_base=ptr;iov0.iov_len=nbytes;msg.msg_iov=iov;msg.msg_iovlen=1;sendmsg(fd,&msg,0);用户凭证#用户凭证#include struct fcred uid_t fc_ruid;/真实 UID gid_t fc_rgid;/真实 GID char fc_loginMAXLOGNAME;/LOGIN 名字 uid_t fc_uid;/有效 UID short fc_ngroups;/组数 gid_t fc_grou

49、psNGROUPS;#define fc_gid fc_groups0;/有效 GID 需要将 LOCAL _CREDS 这个 SOCKET 选项设置为 1,在 TCP 中是 CLIENT 在连接后第一次发送数据时由内核一起发送的,UDP 是每次发送数据都产生 十、网络参数的设置和获取 十、网络参数的设置和获取 获得主机名存到 hostname 中 int gethostname(char*hostname,size_t size);取得本地的 SOCKET 信息 int getsockname(int sockfd,struct sockaddr*addr,int*addrlen);取得对方

50、主机的 SOCKET 信息 int getpeername(int sockfd,struct sockaddr*addr,int*addrlen);获得 DNS 信息:struct hostent*gethostbyname(const char*name);struct hostent*gethostbyaddr(const char*addr,int len,int type);返回了一个指向 struct hostent 的指针,struct hostent 定义如下:struct hostent char*h_name;/*主机域名*/char*h_aliases;/*别名*/int

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com