没有人逼你学C语言,但它在复杂的计算世界中,曲径通幽。
socket相关的数据结构 sockaddr_in sockaddr_in结构体定义在/usr/include/netinet/in.h中,它的定义是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 struct sockaddr_in { __SOCKADDR_COMMON (sin_); in_port_t sin_port; struct in_addr sin_addr ; unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t ) - sizeof (struct in_addr)]; };
这个结构体中又涉及到另外几个类型和宏定义,包括__SOCKADDR_COMMON、in_port_t、in_addr。
__SOCKADDR_COMMON
__SOCKADDR_COMMON定义在bits/sockaddr.h当中,它的作用是将sin_和family参数拼接为对应的sa_family_t类型的地址家族。
1 2 3 4 5 6 7 8 9 typedef unsigned short int sa_family_t ;#define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family
也就是说这个预处理宏定义的意思是将sin_和family拼接在一起构成sa_family_t类型的sin_family。
sa_family_t就是短整形,长度16 bits的整数。
所以sockaddr_in结构体的第一个元素其实是sa_family_t类型的sin_family参数。
in_port_t
in_port_t实际上是uint16_t,16位的无符号整数。
1 typedef uint16_t in_port_t ;
uint16_t其实就是__uint16_t,表示unsigned short int,它的长度是2个字节,能表示的范围是0-65535。
in_addr
这个显而易见,就是表示一个IPv4的地址:
1 2 3 4 5 6 typedef uint32_t in_addr_t ;struct in_addr { in_addr_t s_addr; };
而uint32_t也就是__uint32_t,表示unsigned int,一共4个字节。IP地址一般是拆成点分十进制看的,一个字节能表示的范围是0-255,所以的in_addr也就是能表示成0.0.0.0 ~ 255.255.255.255。
sin_zero
sin_zero的相关定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #if __UAPI_DEF_SOCKADDR_IN #define __SOCK_SIZE__ 16 struct sockaddr_in { __kernel_sa_family_t sin_family; __be16 sin_port; struct in_addr sin_addr ; unsigned char __pad[__SOCK_SIZE__ - sizeof (short int ) - sizeof (unsigned short int ) - sizeof (struct in_addr)]; }; #define sin_zero __pad #endif
__pad声明了一个长素为8个字节的字符数组。
1 2 __SOCK_SIZE__ - sizeof (short int ) - sizeof (unsigned short int ) - sizeof (struct in_addr) = 16 - 2 - 2 - 4 = 8
sin_family的类型
在C语言实现网络通信中,最开始需要做的就是声明并且初始化sockaddr_in结构体。 其中sin_family的类型有这些:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 #define PF_UNSPEC 0 #define PF_LOCAL 1 #define PF_UNIX PF_LOCAL #define PF_FILE PF_LOCAL #define PF_INET 2 #define PF_AX25 3 #define PF_IPX 4 #define PF_APPLETALK 5 #define PF_NETROM 6 #define PF_BRIDGE 7 #define PF_ATMPVC 8 #define PF_X25 9 #define PF_INET6 10 #define PF_ROSE 11 #define PF_DECnet 12 #define PF_NETBEUI 13 #define PF_SECURITY 14 #define PF_KEY 15 #define PF_NETLINK 16 #define PF_ROUTE PF_NETLINK #define PF_PACKET 17 #define PF_ASH 18 #define PF_ECONET 19 #define PF_ATMSVC 20 #define PF_RDS 21 #define PF_SNA 22 #define PF_IRDA 23 #define PF_PPPOX 24 #define PF_WANPIPE 25 #define PF_LLC 26 #define PF_IB 27 #define PF_MPLS 28 #define PF_CAN 29 #define PF_TIPC 30 #define PF_BLUETOOTH 31 #define PF_IUCV 32 #define PF_RXRPC 33 #define PF_ISDN 34 #define PF_PHONET 35 #define PF_IEEE802154 36 #define PF_CAIF 37 #define PF_ALG 38 #define PF_NFC 39 #define PF_VSOCK 40 #define PF_KCM 41 #define PF_QIPCRTR 42 #define PF_SMC 43 #define PF_MAX 44 #define AF_UNSPEC PF_UNSPEC #define AF_LOCAL PF_LOCAL #define AF_UNIX PF_UNIX #define AF_FILE PF_FILE #define AF_INET PF_INET #define AF_AX25 PF_AX25 #define AF_IPX PF_IPX #define AF_APPLETALK PF_APPLETALK #define AF_NETROM PF_NETROM #define AF_BRIDGE PF_BRIDGE #define AF_ATMPVC PF_ATMPVC #define AF_X25 PF_X25 #define AF_INET6 PF_INET6 #define AF_ROSE PF_ROSE #define AF_DECnet PF_DECnet #define AF_NETBEUI PF_NETBEUI #define AF_SECURITY PF_SECURITY #define AF_KEY PF_KEY #define AF_NETLINK PF_NETLINK #define AF_ROUTE PF_ROUTE #define AF_PACKET PF_PACKET #define AF_ASH PF_ASH #define AF_ECONET PF_ECONET #define AF_ATMSVC PF_ATMSVC #define AF_RDS PF_RDS #define AF_SNA PF_SNA #define AF_IRDA PF_IRDA #define AF_PPPOX PF_PPPOX #define AF_WANPIPE PF_WANPIPE #define AF_LLC PF_LLC #define AF_IB PF_IB #define AF_MPLS PF_MPLS #define AF_CAN PF_CAN #define AF_TIPC PF_TIPC #define AF_BLUETOOTH PF_BLUETOOTH #define AF_IUCV PF_IUCV #define AF_RXRPC PF_RXRPC #define AF_ISDN PF_ISDN #define AF_PHONET PF_PHONET #define AF_IEEE802154 PF_IEEE802154 #define AF_CAIF PF_CAIF #define AF_ALG PF_ALG #define AF_NFC PF_NFC #define AF_VSOCK PF_VSOCK #define AF_KCM PF_KCM #define AF_QIPCRTR PF_QIPCRTR #define AF_SMC PF_SMC #define AF_MAX PF_MAX
其中最常用的AF_INET就是PF_INET,也就2所代表的IP协议家族。
sin_addr的赋值 sin_addr需要一个IPv4的地址作为值,in.h中定义了这样几个常用值,其中包括本地地址、多拨地址等:
写服务端socket最常用的INADDR_ANY地址就是((unsigned long int) 0x00000000)
,即 0.0.0.0:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #define INADDR_ANY ((unsigned long int) 0x00000000) #define INADDR_BROADCAST ((unsigned long int) 0xffffffff) #define INADDR_NONE ((unsigned long int) 0xffffffff) #define IN_LOOPBACKNET 127 #define INADDR_LOOPBACK 0x7f000001 #define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) #define INADDR_UNSPEC_GROUP 0xe0000000U #define INADDR_ALLHOSTS_GROUP 0xe0000001U #define INADDR_ALLRTRS_GROUP 0xe0000002U #define INADDR_MAX_LOCAL_GROUP 0xe00000ffU #endif
socket的类型 关于socket的类型,在bits/socket_type.h中定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 enum __socket_type { SOCK_STREAM = 1 , #define SOCK_STREAM SOCK_STREAM SOCK_DGRAM = 2 , #define SOCK_DGRAM SOCK_DGRAM SOCK_RAW = 3 , #define SOCK_RAW SOCK_RAW SOCK_RDM = 4 , #define SOCK_RDM SOCK_RDM SOCK_SEQPACKET = 5 , #define SOCK_SEQPACKET SOCK_SEQPACKET SOCK_DCCP = 6 , #define SOCK_DCCP SOCK_DCCP SOCK_PACKET = 10 , #define SOCK_PACKET SOCK_PACKET SOCK_CLOEXEC = 02000000 , #define SOCK_CLOEXEC SOCK_CLOEXEC SOCK_NONBLOCK = 00004000 #define SOCK_NONBLOCK SOCK_NONBLOCK };
socket相关的函数 主要是定义在sys/socket.h中的以下函数:
socket
bind
listen
accept
connect
关于这些函数的介绍暂不赘述,sys/socket.h里写的很详细。这里用一个socket基础的例子来演示其用法:
服务端server.c :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> int main (int argc, char *argv[]) { int fd, new_fd, struct_len, numbytes; struct sockaddr_in server_addr ; struct sockaddr_in client_addr ; char buff[BUFSIZ]; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8000 ); server_addr.sin_addr.s_addr = INADDR_ANY; bzero(&(server_addr.sin_zero), 8 ); struct_len = sizeof (struct sockaddr_in); fd = socket(AF_INET, SOCK_STREAM, 0 ); while (bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1 ); printf ("Bind Success!\n" ); while (listen(fd, 10 ) == -1 ); printf ("Listening(%d)....\n" , fd); printf ("Ready for Accept...\n" ); while ( new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len) ){ printf ("Get the New Client: %d\n" , new_fd); numbytes = send(new_fd,"Welcome to my server\n" ,21 ,0 ); while ((numbytes = recv(new_fd, buff, BUFSIZ, 0 )) > 0 ) { buff[numbytes] = '\0' ; printf ("%s\n" ,buff); if (send(new_fd,buff,numbytes,0 )<0 ) { perror("write" ); return 1 ; } } close(new_fd); } close(fd); return 0 ; }
客户端client.c :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main (int argc,char *argv[]) { int sockfd,numbytes; char buf[BUFSIZ]; struct sockaddr_in their_addr ; printf ("break!" ); while ((sockfd = socket(AF_INET,SOCK_STREAM,0 )) == -1 ); printf ("We get the sockfd~\n" ); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(8000 ); their_addr.sin_addr.s_addr=inet_addr("127.0.0.1" ); bzero(&(their_addr.sin_zero), 8 ); while (connect(sockfd,(struct sockaddr*)&their_addr,sizeof (struct sockaddr)) == -1 ); printf ("Get the Server~Cheers!\n" ); numbytes = recv(sockfd, buf, BUFSIZ,0 ); buf[numbytes]='\0' ; printf ("%s" ,buf); while (1 ) { printf ("Entersome thing:" ); scanf ("%s" ,buf); numbytes = send(sockfd, buf, strlen (buf), 0 ); numbytes=recv(sockfd,buf,BUFSIZ,0 ); buf[numbytes]='\0' ; printf ("received:%s\n" ,buf); } close(sockfd); return 0 ; }
参考资料 Linux下C语言的socket网络编程 socketpair的用法和理解 进程间通信:管道和socketpair的区别