Linux C网络编程基础

TCP/IP基础

UDP提供无连接服务 
UDP的数据格式:

#ifdef __FAVOR_BSD
struct udphdr {
         u_int16_t uh_sport;           /* source port */
         u_int16_t uh_dport;           /* destination port */
         u_int16_t uh_ulen;            /* udp length */
         u_int16_t uh_sum;             /* udp checksum */
};
#else

struct udphdr {
  u_int16_t     source;
  u_int16_t     dest;
  u_int16_t     len;
  u_int16_t     check;
};
#endif
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TCP是面向连接的,切实全双工的。 
TCP协议数据段: 
这里写图片描述

struct tcphdr {
    WORD    SourPort;
    WORD    DestPort;
    DWORD   SeqNo;
    DWORD   AckNo;
    BYTE        HLen;
    BYTE        Flag;
    WORD    Window;
    WORD    ChkSum;
    WORD    UrgPtr;
    /* Put options here. */
}; 
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

TCP的time_wait: 
执行主动关闭的那端进入这种状态。这个端点在该状态的持续时间是2MSL(最长分节生命周期)。 
网络中的几类地址: 
物理地址:即MAC地址 (数据链路层) 
逻辑地址:即IP地址 
端口地址:应用程序端口号 
域名地址:取代IP地址记忆

IPv4的套接字地址:

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };
/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

IPv6套接字地址:

struct in6_addr
  {
    union
      {
    uint8_t __u6_addr8[16];
#ifdef __USE_MISC
    uint16_t __u6_addr16[8];
    uint32_t __u6_addr32[4];
#endif
      } __in6_u;
#define s6_addr         __in6_u.__u6_addr8
#ifdef __USE_MISC
# define s6_addr16      __in6_u.__u6_addr16
# define s6_addr32      __in6_u.__u6_addr32
#endif
  };

/* Ditto, for IPv6.  */
struct sockaddr_in6
  {
    __SOCKADDR_COMMON (sin6_);
    in_port_t sin6_port;    /* Transport layer port # */
    uint32_t sin6_flowinfo; /* IPv6 flow information */
    struct in6_addr sin6_addr;  /* IPv6 address */
    uint32_t sin6_scope_id; /* IPv6 scope-id */
  };
   
   
  • 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
  • 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

TCP套接字编程

tcp套接字网络编程的主要实现过程: 
这里写图片描述 
关于socket函数:

#include<sys/socket.h>
int socket(int family,int type,int protocol)
   
   
  • 1
  • 2
  • 1
  • 2

family指明了协议族。例如:AF_INET(IPv4协议);AF_INET6(IPV6协议);AF_ROUTE(路由套接口) 
type指明了套接字类型。例如: 
SOCK_STREAM字节流套接口(TCP); 
SOCK_DGRAM数据包套接口(UDP); 
SOCK_RAW原始套接口

protocol指明协议标志

端口与套接字

端口:访问网络不同计算机程序的编号 
IP地址标记了不同的电脑,而域名则是iP地址便于记忆的别名

edemon@ubuntu:~$ ping www.baidu.com 
PING www.a.shifen.com (119.75.218.70) 56(84) bytes of data. 
这里写图片描述
socket的本义是插座。描述计算机之间不同程序之间的通信方式。TCP和UDP会遇到同时为多个应用程序同时并发进行通信的问题,为了区分不同的应用进程的应用和连接,需要使用应用程序与TCP/IP协议交互的套接字接口。 
套接字:传输层协议+端口号+IP地址

域名和IP的相互转换

IP地址和网络地址: 
网络地址很大一部分是由地址掩码决定的。 
IP 转 domain:

#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h> 
#include <netinet/in.h>
#include <arpa/inet.h>  
#include <errno.h> 
#include <string.h>

int  main()
{
   struct hostent *host;
   char addr[]="208.108.249.216"; //202.108.249.216  61.135.169.121   http://61.135.169.125/
   struct in_addr in;
   struct sockaddr_in addr_in; 

   host=gethostbyaddr(addr,sizeof(addr),AF_INET);
   if(host!=(struct hostent *)NULL)
   {
       memcpy(&addr_in.sin_addr.s_addr,host->h_addr,4);
       in.s_addr=addr_in.sin_addr.s_addr;
       printf("Domain name: %s \n",host->h_name);
       printf("IP length:    %d\n",host->h_length);
       printf("Type:    %d\n",host->h_addrtype);
       printf("IP          : %s \n",inet_ntoa(in));
    }
    else
    {  
        char *buffer = strerror(errno); 
          printf("%s\n",buffer);
    } 
}
/*
Domain name: 50-48-56-46.dr05.nrwc.ny.frontiernet.net 
IP length:    16
Type:    2
IP          : 50.48.56.46 
*/
   
   
  • 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
  • 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

domain 转IP:

#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int  main()
{
   struct hostent *host;
   char hostname[]="www.baidu.com";
   char hostname2[]="www.012www.com";
   struct in_addr in;
   struct sockaddr_in sock_in;
   extern int h_errno;

   if((host=gethostbyname(hostname))!=NULL){
       //printf("%s\n",host->h_addr);
       memcpy(&sock_in.sin_addr.s_addr, host->h_addr, 4);
       in.s_addr=sock_in.sin_addr.s_addr;
       printf("Domain name: %s \n",hostname);
       printf("IP length:    %d\n",host->h_length);
       printf("Type:    %d\n",host->h_addrtype);
       /*inet_ntoa()用来将参数in所指的网络二进制的数字转换成网络地址,
       然后将指向此网络地址字符串的指针返回。*/
       printf("IP          : %s \n",inet_ntoa(in));
    }
    else{
        printf("Domain name: %s \n",hostname);
        printf("error: %d\n",h_errno);
        printf("%s\n",hstrerror(h_errno));
    }

   if((host=gethostbyname(hostname2))!=NULL){
       memcpy(&sock_in.sin_addr.s_addr,host->h_addr,4);
       in.s_addr=sock_in.sin_addr.s_addr;
       printf("Domain name: %s \n",hostname2);
       printf("IP          : %s \n",inet_ntoa(in));
       printf("IP length:    %d\n",host->h_length);
       printf("Type:    %d\n",host->h_addrtype);
    }
    else{
        printf("Domain name: %s \n",hostname2);
        printf("error: %d\n",h_errno);
            printf("%s\n",hstrerror(h_errno));
    }
}
/*
Domain name: www.baidu.com 
IP length:    4
Type:    2
IP          : 61.135.169.121 
Domain name: www.012www.com 
error: 1
Unknown host
*/
   
   
  • 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
  • 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

网络地址转换

对于不同的socket domain定义了一个通用的数据结构——套接字结构:

struct sockaddr
{
unsigned short int sa_family;
char sa_data[14];
};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

sa_family 为调用socket()时的domain参数,即AF_xxxx值。 
sa_data 最多使用14个字符长度。 
此sockaddr结构会因使用不同的socket domain而有不同结构定义,例如使用AF_INET domain,其 
socketaddr结构定义便为

struct socketaddr_in
{
unsigned short int sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr
{
uint32_t s_addr;
};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

sin_family 即为sa_family 
sin_port 为使用的port编号 
sin_addr.s_addr 为IP 地址 
sin_zero 未使用。

struct hostent{
char * h_name;
char ** h_aliases;
short h_addrtype;
short h_length;
char ** h_addr_list;
};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

主机字节序和网络字节序的转换:

unsigned long int htonl(unsigned long int hostlong); 
将32位主机字符顺序转换成网络字符顺序 
unsigned short int htons(unsigned short int hostshort); 
将16位主机字符顺序转换成网络字符顺序 
unsigned long int ntohl(unsigned long int netlong); 
将32位网络字符顺序转换成主机字符顺序 
unsigned short int ntohs(unsigned short int netshort); 
将16位网络字符顺序转换成主机字符顺序

#include <stdio.h>
#include <arpa/inet.h>

int  main()
{
   long local;
   int port;
   local =123456;
   port=123456;
   printf("host 32 %ld -> net 32: %d\n",local,htonl(local));
   printf("host 16 %d -> net 16: %d\n",port,htons(port));
   printf("net 32 %d -> host 32: %d\n",htonl(local),ntohl(htonl(local)));
   printf("net 16 %d -> host 16: %d\n",htons(port),ntohs(htons(port)));  
   return 0;
}
/*
host 32 123456 -> net 32: 1088553216
host 16 123456 -> net 16: 16610
net 32 1088553216 -> host 32: 123456
net 16 16610 -> host 16: 57920
*/
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

long inet_addr(char *str) 
将网络IP地址转化成10进制长整型数 
头文件:

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

char *inet_ntoa(struct in_addr in); 
将整数型地址转化成点分十进制地址(在计算机中经常使用长整型数表示IP地址) 
表头文件

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

例子:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int  main()
{
   struct in_addr ip;
   ip.s_addr=16885952;
   char *str=inet_ntoa(ip);
   printf("%s\n",str);
   printf("%u\n", inet_addr(str));
}
/*
192.168.1.1
16885952
*/
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

系统支持的网络服务

cat /etc/protocols
……
daytime     13/tcp
daytime     13/udp
netstat     15/tcp   
qotd        17/tcp      quote
msp     18/tcp              # message send protocol
msp     18/udp
chargen     19/tcp      ttytst source
chargen     19/udp      ttytst source
ftp-data    20/tcp
ftp     21/tcp
……
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

获取服务信息:

#include <stdio.h>
#include <netdb.h>   

int  main()
{
    struct servent *ser;
    if( ser=getservbyname("http","tcp"))  //通过名字获取网络服务
    {
       printf("name : %s\n",ser->s_name);
       printf("net port: %d  ", ser->s_port);
       printf("host port : %d\n",ntohs(ser->s_port));  //16位网络字符顺序转换成主机字符顺序
       printf("protocol:%s\n",ser->s_proto);
       printf("alias: %s\n",ser->s_aliases[0]);
    }
    else
    {
        printf("there is no such a service.\n");
    }
    puts("---------------------------------------------");
    if( ser=getservbyname("hehe","tcp"))
    {
       printf("name : %s\n",ser->s_name);
       printf("net port: %d  ", ser->s_port);
       printf("host port : %d\n",ntohs(ser->s_port));
       printf("protocol:%s\n",ser->s_proto);
       printf("alias: %s\n",ser->s_aliases[0]);
    }
    else
    {
        printf("there is no such a service.\n");
    }   
    puts("---------------------------------------------");  //通过端口号获取网络服务
    if( ser=getservbyport(htons(21),"tcp"))  //将16位主机字符顺序转换成网络字符顺序
    {
       printf("name : %s\n",ser->s_name);
       printf("net port: %d  ", ser->s_port);
       printf("host port : %d\n",ntohs(ser->s_port));  
       printf("protocol:%s\n",ser->s_proto);
       printf("alias: %s\n",ser->s_aliases[0]);
    }
    else
    {
        printf("there is no such a service.\n");
    }
}
/*
name : http
net port: 20480  host port : 80
protocol:tcp
alias: www
---------------------------------------------
there is no such a service.
---------------------------------------------
name : ftp
net port: 5376  host port : 21
protocol:tcp
alias: (null)
*/
   
   
  • 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
  • 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

捕获错误

void herror(const char *s); 
可以显示网络函数上出现的错误。先输出这个字符串,然后输出错误信息。 
extern int h_errno 
可以捕获错误编号。 
char *hstrerror(int err) 
返回错误编码对应的错误信息。 
三个和错误相关的函数或变量都与头文件netdb.h相关

#include <stdio.h>
#include <netdb.h>
int  main()
{
    herror("result : ");
    extern int h_errno;
    printf("%s\n", hstrerror(h_errno));
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

获取协议数据

系统支持的协议:

ip  0   IP      # internet protocol, pseudo protocol number
hopopt  0   HOPOPT      # IPv6 Hop-by-Hop Option [RFC1883]
icmp    1   ICMP        # internet control message protocol
igmp    2   IGMP        # Internet Group Management
ggp 3   GGP     # gateway-gateway protocol
ipencap 4   IP-ENCAP    # IP encapsulated in IP (officially ``IP'')
st  5   ST      # ST datagram mode
tcp 6   TCP     # transmission control protocol
egp 8   EGP     # exterior gateway protocol
igp 9   IGP     # any private interior gateway (Cisco)
pup 12  PUP     # PARC universal packet protocol
udp 17  UDP     # user datagram protocol
hmp 20  HMP     # host monitoring protocol
xns-idp 22  XNS-IDP     # Xerox NS IDP
rdp 27  RDP     # "reliable datagram" protocol
iso-tp4 29  ISO-TP4     # ISO Transport Protocol class 4 [RFC905]
dccp    33  DCCP        # Datagram Congestion Control Prot. [RFC4340]
xtp 36  XTP     # Xpress Transfer Protocol
ddp 37  DDP     # Datagram Delivery Protocol
idpr-cmtp 38    IDPR-CMTP   # IDPR Control Message Transport
ipv6    41  IPv6        # Internet Protocol, version 6
ipv6-route 43   IPv6-Route  # Routing Header for IPv6
ipv6-frag 44    IPv6-Frag   # Fragment Header for IPv6
idrp    45  IDRP        # Inter-Domain Routing Protocol
rsvp    46  RSVP        # Reservation Protocol
gre 47  GRE     # General Routing Encapsulation
esp 50  IPSEC-ESP   # Encap Security Payload [RFC2406]
ah  51  IPSEC-AH    # Authentication Header [RFC2402]
skip    57  SKIP        # SKIP
ipv6-icmp 58    IPv6-ICMP   # ICMP for IPv6
ipv6-nonxt 59   IPv6-NoNxt  # No Next Header for IPv6
ipv6-opts 60    IPv6-Opts   # Destination Options for IPv6
rspf    73  RSPF CPHB   # Radio Shortest Path First (officially CPHB)
vmtp    81  VMTP        # Versatile Message Transport
eigrp   88  EIGRP       # Enhanced Interior Routing Protocol (Cisco)
ospf    89  OSPFIGP     # Open Shortest Path First IGP
ax.25   93  AX.25       # AX.25 frames
ipip    94  IPIP        # IP-within-IP Encapsulation Protocol
etherip 97  ETHERIP     # Ethernet-within-IP Encapsulation [RFC3378]
encap   98  ENCAP       # Yet Another IP encapsulation [RFC1241]
#   99          # any private encryption scheme
pim 103 PIM     # Protocol Independent Multicast
ipcomp  108 IPCOMP      # IP Payload Compression Protocol
vrrp    112 VRRP        # Virtual Router Redundancy Protocol [RFC5798]
l2tp    115 L2TP        # Layer Two Tunneling Protocol [RFC2661]
isis    124 ISIS        # IS-IS over IPv4
sctp    132 SCTP        # Stream Control Transmission Protocol
fc  133 FC      # Fibre Channel
mobility-header 135 Mobility-Header # Mobility Support for IPv6 [RFC3775]
udplite 136 UDPLite     # UDP-Lite [RFC3828]
mpls-in-ip 137  MPLS-in-IP  # MPLS-in-IP [RFC4023]
manet   138         # MANET Protocols [RFC5498]
hip 139 HIP     # Host Identity Protocol
shim6   140 Shim6       # Shim6 Protocol [RFC5533]
wesp    141 WESP        # Wrapped Encapsulating Security Payload
rohc    142 ROHC        # Robust Header Compression
   
   
  • 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
  • 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

获取协议信息的例子:

#include <stdio.h>
#include <netdb.h>   

int  main()
{
    struct protoent *pro;
    pro=getprotobyname("tcp");  // by protocol name 
    printf("protocol name : %s\n",pro->p_name);  
    printf("protocol number : %d\n",pro->p_proto);
    printf("protocol alias: %s\n",pro->p_aliases[0]);
    puts("------------------------------");
    pro=getprotobynumber(2);   // by protocol number 
    printf("protocol name : %s\n",pro->p_name);  
    printf("protocol number : %d\n",pro->p_proto);
    printf("protocol alias: %s\n",pro->p_aliases[0]);
}

protocol name : tcp
protocol number : 6
protocol alias: TCP
------------------------------
protocol name : igmp
protocol number : 2
protocol alias: IGMP
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

其他的套接字函数

自己的主机IP地址: 
ifconfig 
下面是ANSI C 中的字节操作函数: 
1. 
void *memset(void *s, int c, size_t n); 
memset()会将参数s所指的内存区域前n个字节以参数c填入,然后返回指向s的指针。 
2. 
void *memcpy(void *dest, const void *src, size_t n); 
memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是, 
memcpy()会完整的复制n个字节,不会因为遇到字符串结束’\0’而结束。 
3. 
int memcmp(const void *s1, const void *s2, size_t n); 
memcmp()用来比较s1和s2所指的内存区间前n个字符。

字符串IP和二进制IP的相互转换(仅能处理IPv4): 
int inet_aton(const char *cp, struct in_addr *inp); 
函数说明 
inet_aton()用来将参数cp所指的网络地址字符串转换成网络使用的二进制的数字,然后存于参数inp所 
指的in_addr结构中。

返回值 
成功则返回非0值,失败则返回0。

#include <stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main(){
    struct in_addr numstr;
    char IP[20]="192.160.8.60";
    if(inet_aton(IP,&numstr)){
         printf("0x%x\n",numstr.s_addr);
    }    
    return 0;
}
/*
0x3c08a0c0
*/
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

inet_pton 
int inet_pton(int af, const char *src, void *dst); 
用于点分十进制转成二进制整数(16进制)。 
成功返回1,af无效返回0,出错返回-1,指针dst存储得到的IP地址。

inet_ntop 
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); 
二进制整数(16进制)转换成点分十进制。 
两者可以同时处理IPv4, IPv6. 
AF_INET 是一个IPv4 网络协议的套接字类型

#include <stdio.h>
#include <arpa/inet.h>
int main ()
{
    char IPstr1[20]="192.18.0.9"; 
    char IPstr2[20];
    struct in_addr s; // IPv4地址结构体

    printf("%d\n",AF_INET);
    inet_pton(AF_INET, IPstr1, (void *)&s);
    printf("inet_pton: 0x%x\n", s.s_addr); //二进制整数(16进制)字节序

    inet_ntop(AF_INET, (void *)&s, IPstr2, sizeof(IPstr2));
    printf("inet_ntop: %s\n", IPstr2); //点分十进制

    return 0;
}
/*
2
inet_pton: 0x90012c0
inet_ntop: 192.18.0.9
*/
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

从进程到内核传递套接字地址结构的函数常有3个——bind, connect, sendto 
从内核到进程传递套接字地址结构的函数常有四个accept, recvfrom, getsockname, getpeername 
bind()对socket定位

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux C网络编程教程及源码是帮助学习者理解和掌握在Linux操作系统下使用C语言进行网络编程的教程和源代码。网络编程是指利用计算机网络进行数据交换和通信的过程,是现代计算机科学中非常重要的一部分。 在Linux操作系统下进行网络编程,我们需要了解一些重要的概念和技术。首先,我们需要学习Socket编程,Socket是一种通信机制,也是网络编程基础。通过创建Socket对象,我们可以建立和管理网络连接,进行数据的传输和接收。 其次,我们需要了解网络协议的基本原理和常用协议的使用,如TCP/IP协议族。TCP/IP协议族是Internet上数据通信的基础协议,包括了TCP(传输控制协议)和IP(Internet协议)等。通过学习TCP/IP协议的原理和使用方法,我们可以实现可靠的网络通信。 最后,我们需要学习一些常见的网络编程库和工具,如libevent、libuv等。这些库可以帮助我们简化网络编程的过程,提供了一些高级的接口和功能,让网络编程更加方便和高效。 教程和源码可以帮助学习者理解和实践网络编程的过程。教程中通常包含了一些基本的概念、示例代码和实战案例,可以帮助学习者逐步掌握网络编程的技能。而源码则为学习者提供了一些实际项目中的代码实现,通过阅读和理解源码,学习者可以更深入地了解网络编程的原理和实践技巧。 总之,Linux C网络编程教程及源码为学习者提供了学习和实践网络编程的指导和资源,通过系统地学习和实践,学习者可以掌握Linux下使用C语言进行网络编程的技能,为日后的软件开发和网络应用提供基础和保障。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值