转载自:http://www.tuicool.com/articles/Yre2Un
已经工作了接近一年的时间,工作之余也只能看看书,了解一下相关的技术细节,在网络设备公司不可避免的要和socket打交道,但通常都是调用公司封装好的接口,没有去考虑这些封装背后的工作,回过头来看真的觉得进步很小,我只能逼自己看看书,看看一些好的代码。
sendmsg和recvmsg这两个接口是高级套接口,这两个接口支持一般数据的发送和接收,还支持多缓冲区的报文发送和接收(readv和sendv支持多缓冲区发送和接收),还可以在报文中带辅助数据。这些功能是常用的send、recv等接口无法完成的。 接口的声明如下:点击( 此处 )折叠或打开
- #include < sys / socket . h >
- ssize_t recvmsg ( int sockfd , struct msghdr * msg , int flags ) ;
- ssize_t sendmsg ( int sockfd , struct msghdr * msg , int flags ) ;
点击( 此处 )折叠或打开
- struct msghdr {
- void * msg_name ; / * 消息的协议地址 * /
- socklen_t msg_namelen ; / * 地址的长度 * /
- struct iovec * msg_iov ; / * 多io缓冲区的地址 * /
- int msg_iovlen ; / * 缓冲区的个数 * /
- void * msg_control ; / * 辅助数据的地址 * /
- socklen_t msg_controllen ; / * 辅助数据的长度 * /
- int msg_flags ; / * 接收消息的标识 * /
- } ;
接下来的两个成员是关于接受和发送数据的的。其中的strcut iovec是io向量,如下所示:
点击( 此处 )折叠或打开
- struct iovec {
- void * io_base ; / * buffer空间的基地址 * /
- size_t iov_len ; / * 该buffer空间的长度 * /
- } ;
点击( 此处 )折叠或打开
- struct cmsghdr {
- socklen_t cmsg_len ; / * 包含该头部的数据长度 * /
- int cmsg_level ; / * 具体的协议标识 * /
- int cmsg_type ; / * 协议中的类型 * /
- } ;
- 其中的cmsg_level主要包含IPPROTO_IP ( ipv ) , IPPROTO_IPV6 ( ipv6 ) , SOL_SOCKET ( unix domain ) .
- 其中的cmsg_type是根据上述的类型有分别有不同的内容,比如SOL_SOCKET中主要包含:SCM_RIGHTS(发送接收描述字), SCM_CREDS(发送接收用户凭证)
点击( 此处 )折叠或打开
- 服务器端接收客户端发送过来的描述字:
- #include "unp.h"
- int main ( int argc , char * argv [ ] )
- {
- int clifd , listenfd ;
- struct sockaddr_un servaddr , cliaddr ;
- int ret ;
- socklen_t clilen ;
- struct msghdr msg ;
- struct iovec iov [ 1 ] ;
- char buf [ 100 ] ;
- char * testmsg = "test msg.\n" ;
- union {
- struct cmsghdr cm ;
- char control [ CMSG_SPACE ( sizeof ( int ) ) ] ;
- } control_un ;
- struct cmsghdr * pcmsg ;
- int recvfd ;
- listenfd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
- if ( listenfd < 0 ) {
- printf ( "socket failed.\n" ) ;
- return - 1 ;
- }
- unlink ( UNIXSTR_PATH ) ;
- bzero ( & servaddr , sizeof ( servaddr ) ) ;
- servaddr . sun_family = AF_UNIX ;
- strcpy ( servaddr . sun_path , UNIXSTR_PATH ) ;
- ret = bind ( listenfd , ( SA * ) & servaddr , sizeof ( servaddr ) ) ;
- if ( ret < 0 ) {
- printf ( "bind failed. errno = %d.\n" , errno ) ;
- close ( listenfd ) ;
- return - 1 ;
- }
- listen ( listenfd , 5 ) ;
- while ( 1 ) {
- clilen = sizeof ( cliaddr ) ;
- clifd = accept ( listenfd , ( SA * ) & cliaddr , & clilen ) ;
- if ( clifd < 0 ) {
- printf ( "accept failed.\n" ) ;
- continue ;
- }
- msg . msg_name = NULL ;
- msg . msg_namelen = 0 ;
- iov [ 0 ] . iov_base = buf ;
- iov [ 0 ] . iov_len = 100 ;
- msg . msg_iov = iov ;
- msg . msg_iovlen = 1 ;
- msg . msg_control = control_un . control ;
- msg . msg_controllen = sizeof ( control_un . control ) ;
- ret = recvmsg ( clifd , & msg , 0 ) ;
- if ( ret < = 0 ) {
- return ret ;
- }
- if ( ( pcmsg = CMSG_FIRSTHDR ( & msg ) ) ! = NULL & & ( pcmsg - >cmsg_len = = CMSG_LEN ( sizeof ( int ) ) ) ) {
- if ( pcmsg - > cmsg_level ! = SOL_SOCKET ) {
- printf ( "cmsg_leval is not SOL_SOCKET\n" ) ;
- continue ;
- }
- if ( pcmsg - > cmsg_type ! = SCM_RIGHTS ) {
- printf ( "cmsg_type is not SCM_RIGHTS" ) ;
- continue ;
- }
- recvfd = * ( ( int * ) CMSG_DATA ( pcmsg ) ) ;
- printf ( "recv fd = %d\n" , recvfd ) ;
- write ( recvfd , testmsg , strlen ( testmsg ) + 1 ) ;
- }
- }
- return 0 ;
- }
点击( 此处 )折叠或打开
- #include "unp.h"
- #define OPEN_FILE "test"
- int main ( int argc , char * argv [ ] )
- {
- int clifd ;
- struct sockaddr_un servaddr ;
- int ret ;
- struct msghdr msg ;
- struct iovec iov [ 1 ] ;
- char buf [ 100 ] ;
- union {
- struct cmsghdr cm ;
- char control [ CMSG_SPACE ( sizeof ( int ) ) ] ;
- } control_un ;
- struct cmsghdr * pcmsg ;
- int fd ;
- clifd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
- if ( clifd < 0 ) {
- printf ( "socket failed.\n" ) ;
- return - 1 ;
- }
- fd = open ( OPEN_FILE , O_CREAT | O_RDWR , 0777 ) ;
- if ( fd < 0 ) {
- printf ( "open test failed.\n" ) ;
- return - 1 ;
- }
- bzero ( & servaddr , sizeof ( servaddr ) ) ;
- servaddr . sun_family = AF_UNIX ;
- strcpy ( servaddr . sun_path , UNIXSTR_PATH ) ;
- ret = connect ( clifd , ( SA * ) & servaddr , sizeof ( servaddr ) ) ;
- if ( ret < 0 ) {
- printf ( "connect failed.\n" ) ;
- return 0 ;
- }
- msg . msg_name = NULL ;
- msg . msg_namelen = 0 ;
- iov [ 0 ] . iov_base = buf ;
- iov [ 0 ] . iov_len = 100 ;
- msg . msg_iov = iov ;
- msg . msg_iovlen = 1 ;
- msg . msg_control = control_un . control ;
- msg . msg_controllen = sizeof ( control_un . control ) ;
- pcmsg = CMSG_FIRSTHDR ( & msg ) ;
- pcmsg - > cmsg_len = CMSG_LEN ( sizeof ( int ) ) ;
- pcmsg - > cmsg_level = SOL_SOCKET ;
- pcmsg - > cmsg_type = SCM_RIGHTS ;
- * ( ( int * ) CMSG_DATA ( pcmsg ) ) = = fd ;
- ret = sendmsg ( clifd , & msg , 0 ) ;
- printf ( "ret = %d.\n" , ret ) ;
- return 0 ;
- }