网络编程中

网络相关概念

(1)套接口的概念:
套接口,也叫“套接字”。是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。它是网络进程的ID。网络通信,归根到底还是进程间的通信(不同计算机上的进程间通信)。在网络中,每一个节点(计算机或路由)都有一个网络地址,也就是IP地址。两个进程通信时,首先要确定各自所在的网络节点的网络地址。但是,网络地址只能确定进程所在的计算机,而一台计算机上很可能同时运行着多个进程,所以仅凭网络地址还不能确定到底是和网络中的哪一个进程进行通信,因此套接口中还需要包括其他的信息,也就是端口号(PORT)。在一台计算机中,一个端口号一次只能分配给一个进程,也就是说,在一台计算机中,端口号和进程之间是一一对应关系。所以,使用端口号和网络地址的组合可以唯一的确定整个网络中的一个网络进程。

例如,如网络中某一台计算机的IP为10.92.20.160,操作系统分配给计算机中某一应用程序进程的端口号为1500,则此时 10.92.20.160  1500就构成了一个套接口。

(2)端口号的概念:

在网络技术中,端口大致有两种意思:一是物理意义上的端口,如集线器、交换机、路由器等用于连接其他网络设备的接口。二是指TCP/IP协议中的端口,端口号的范围从0~65535,一类是由互联网指派名字和号码公司ICANN负责分配给一些常用的应用程序固定使用的“周知的端口”,其值一般为0~1023.例如http的端口号是80,ftp为21,ssh为22,telnet为23等。还有一类是用户自己定义的,通常是大于1024的整型值。

(3)ip地址的表示:
通常用户在表达IP地址时采用的是点分十进制表示的数值(或者是为冒号分开的十进制Ipv6地址),而在通常使用的socket编程中使用的则是二进制值,这就需要将这两个数值进行转换。

ipv4地址:32bit, 4字节,通常采用点分十进制记法。

例如对于:10000000 00001011 00000011 00011111

点分十进制表示为:128.11.3.31

2.1. socket概念
Linux中的网络编程是通过socket接口来进行的。socket是一种特殊的I/O接口,它也是一种文件描述符。它是一种常用的进程之间通信机制,通过它不仅能实现本地机器上的进程之间的通信,而且通过网络能够在不同机器上的进程之间进行通信。

每一个socket都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的;

2.2. socket类型
(1)流式socket(SOCK_STREAM) à用于TCP通信

流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。

(2)数据报socket(SOCK_DGRAM) à用于UDP通信

数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP。

(3)原始socket (SOCK_RAW) à用于新的网络协议实现的测试等

原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用较为不便,主要用于一些协议的开发。

2.3. socket信息数据结构

 1struct sockaddr
 2{
 3    unsigned short sa_family; /地址族/
 4    char sa_data[14]; /14字节的协议地址,包含该socket的IP地址和端口号。/
 5};
 6struct sockaddr_in
 7{
 8    short int sa_family; /地址族/
 9    unsigned short int sin_port; /端口号/
10    struct in_addr sin_addr; /IP地址/
11    unsigned char sin_zero[8]; /填充0 以保持与struct sockaddr同样大小/
12};
13struct in_addr
14{
15unsigned long int  s_addr; / 32位IPv4地址,网络字节序 /
16};
17头文件
18sa_family:AF_INET  aIPv4协议   AF_INET6  àIPv6协议

2.4. 数据存储优先顺序的转换
计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。内存的低地址存储数据的低字节,高地址存储数据的高字节的方式叫小端模式。内存的高地址存储数据的低字节,低地址存储数据高字节的方式称为大端模式。

eg:对于内存中存放的数0x12345678来说

如果是采用大端模式存放的,则其真实的数是:0x12345678

如果是采用小端模式存放的,则其真实的数是:0x78563412

如果称某个系统所采用的字节序为主机字节序,则它可能是小端模式的,也可能是大端模式的。而端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式。要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储优先顺序进行相互转化。这里用到四个函数:htons(),ntohs(),htonl()和ntohl().这四个地址分别实现网络字节序和主机字节序的转化,这里的h代表host,n代表network,s代表short,l代表long。通常16位的IP端口号用s代表,而IP地址用l来代表。

函数原型如下:

 1#include <sys/socket.h>
 2
 3#include <netinet/in.h>
 4
 5#include <arpa/inet.h>
 6
 7int inet_aton(const char *straddr, struct in_addr *addrptr);
 8
 9char *inet_ntoa(struct in_addr inaddr);
10
11in_addr_t inet_addr(const char *straddr);

2.5. 地址格式转化
通常用户在表达地址时采用的是点分十进制表示的数值(或者是为冒号分开的十进制Ipv6地址),而在通常使用的socket编程中使用的则是32位的网络字节序的二进制值,这就需要将这两个数值进行转换。这里在Ipv4中用到的函数有inet_aton()、inet_addr()和inet_ntoa(),而IPV4和Ipv6兼容的函数有inet_pton()和inet_ntop()。

IPv4的函数原型:

 1#include <sys/socket.h>
 2
 3#include <netinet/in.h>
 4
 5#include <arpa/inet.h>
 6
 7int inet_aton(const char *straddr, struct in_addr *addrptr);
 8
 9char *inet_ntoa(struct in_addr inaddr);
10
11in_addr_t inet_addr(const char *straddr);

函数inet_aton():将点分十进制数的IP地址转换成为网络字节序的32位二进制数值。返回值:成功,则返回1,不成功返回0.
参数straddr:存放输入的点分十进制数IP地址字符串。
参数addrptr:传出参数,保存网络字节序的32位二进制数值。
函数inet_ntoa():将网络字节序的32位二进制数值转换为点分十进制的IP地址。
函数inet_addr():功能与inet_aton相同,但是结果传递的方式不同。inet_addr()若成功则返回32位二进制的网络字节序地址。

IPv4和IPv6的函数原型:

1#include <arpa/inet.h>
2
3int inet_pton(int family, const char *src, void *dst);
4
5const char *inet_ntop(int family, const void *src, char *dst, socklen_t len);

函数inet_pton跟inet_aton实现的功能类似,只是多了family参数,该参数指定为AF_INET,表示是IPv4协议,如果是AF_INET6,表示IPv6协议。
函数inet_ntop跟inet_ntoa类似,其中len表示表示转换之后的长度(字符串的长度)。

 1Example:
 2#include <stdio.h>
 3#include <sys/socket.h>
 4#include <netinet/in.h>
 5#include <arpa/inet.h>
 6int main()
 7{
 8    char ip[] = "192.168.0.101";
 9    struct in_addr myaddr;
10    /* inet_aton */
11    int iRet = inet_aton(ip, &myaddr);
12    printf("%x\n", myaddr.s_addr);
13
14   /* inet_addr */
15   printf("%x\n", inet_addr(ip));
16
17   /* inet_pton */
18   iRet = inet_pton(AF_INET, ip, &myaddr);
19   printf("%x\n", myaddr.s_addr);
20
21   myaddr.s_addr = 0xac100ac4;
22   /* inet_ntoa */
23   printf("%s\n", inet_ntoa(myaddr));
24
25   /* inet_ntop */
26   inet_ntop(AF_INET, &myaddr, ip, 16);
27   puts(ip);
28    return 0;
29}

2.6. 名字地址转化
通常,人们在使用过程中都不愿意记忆冗长的IP地址,尤其到Ipv6时,地址长度多达128位,那时就更加不可能一次性记忆那么长的IP地址了。因此,使用主机名或域名将会是很好的选择。主机名与域名的区别:主机名通常在局域网里面使用,通过/etc/hosts文件,主机名可以解析到对应的ip;域名通常是再internet上使用。

众所周知,百度的域名为:www.baidu.com,而这个域名其实对应了一个百度公司的IP地址,那么百度公司的IP地址是多少呢?我们可以利用ping www.baidu.com来得到百度公司的ip地址,如图。那么,系统是如何将www.baidu.com 这个域名转化为IP地址220.181.111.148的呢?

在linux中,有一些函数可以实现主机名和地址的转化,最常见的有gethostbyname()、gethostbyaddr()等,它们都可以实现IPv4和IPv6的地址和主机名之间的转化。其中gethostbyname()是将主机名转化为IP地址,gethostbyaddr()则是逆操作,是将IP地址转化为主机名。

函数原型:

1#include <netdb.h>
2struct hostent* gethostbyname(const char* hostname);
3struct hostent* gethostbyaddr(const char* addr, size_t len, int family);

推荐阅读:

网络编程<一>

Linux I/O复用--epoll

Linux I/O复用——poll()

Linux I/O复用—select()

线程池网络服务

多线程网络服务

Socket网络编程

线程高级操作

Linux多线程编程

线程

进程间通信(IPC)

进程间通信(一)

进程间通信(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值