一、套接字
在网络中用来描述计算机中不同程序与其他计算机程序通信的方式。为了区分不同应用程序的进程和连接,需要使用应用程序与TCP/IP协议交互的套接字端口。
主要用到三个参数:通信的目的IP地址、使用的传输协议(TCP或UDP)和使用的端口号。
1.套接字相关的数据类型
套接字编程是,通常使用sockaddr和sockaddr_in这两个系统中定义的数据类型结构体。
struct sockaddr
{
unsigned short int sa_family; //指定通信的地址类型,如果是TCP/IP通信,则为AF_INET。
char sa_data[14]; //最多使用14个字符长度,用来保存ip地址和端口信息。
}
sockaddr_in的功能和sockaddr相同,不同的是ip地址和端口分开为不同的成员。
struct sockaddr_in
{
unsigned short in sin_family; //和sa_family相同
uint16_t sin_port; //端口号
struct in_addr sin_addr; //ip地址
unsigned char sin_zero[8]; //未使用字段
}
in_addr也是个结构体,作用是用来保存ip地址。
struct in_addr
{
uint32_t s_addr;//四个字节的ip地址
}
2.套接字类型
套接字类型指的是在网络通信中不同的数据传输方式:
- 流套接字(SOCK_STREAM):使用面向连接的可靠的数据通信方式,即TCP(Transmission Control Protocol)协议。
- 数据报套接字(Raw Sockets):使用不面向连接的数据通信方式,即UDP(User Datagram Protocol)协议。
- 原始套接字(SOCK_RAW):前面讲述的两种套接字是系统定义的,所有的信息头需要按照这种方式进行封装。原始套接字是没有经过处理的ip数据报,可以根据自己的程序的要求进行封装。如果要访问其他协议,则需要使用原始套接字来构造相应协议。
二、域名与ip地址
1. 使用域名获得主机的ip地址
使用域名获得主机的ip地址函数是:gethostbyname();返回一个主机地址结构体。
struct hostent *gethostbyname(const char *name);
hostent主机地址结构体:
struct hostent
{
char *h_name; //Official name of host.
char **h_aliases; // Alias list.
int h_addrtype; // Host address type.
int h_length; // Length of address.
char **h_addr_list; // List of addresses from name server.
}
实例:
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
extern int h_errno; //捕捉网络错误
struct hostent *host;
char hostname[] = "www.163.com";
char hostname2[] = "www.sjaife.com"; //不存在的域名
struct in_addr in;
memset(&in,0,sizeof(in));
if((host = gethostbyname(hostname)) != NULL){
memcpy(&in.s_addr,host->h_addr_list,4); //将地址复制给结构体
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)); //将十进制地址转换为网络ip地址
}else{
printf("Domain name: %s \n",hostname);
printf("error: %d\n",h_errno);
printf("%s\n",hstrerror(h_errno)); //hstrerror函数将错误号转换为提示的错误字符串
}
printf("-------------------------------\n");
if((host = gethostbyname(hostname2)) != NULL){
memcpy(&in.s_addr,host->h_addr_list,4);
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{
printf("Domain name: %s \n",hostname2);
printf("error: %d\n",h_errno);
printf("%s\n",strerror(h_errno));
}
return 0;
}
/*
输出结果
Domain name:www.163.com
IP length : 4
Type : 2
IP : 228.154.106.0
-------------------------------
Domain name: www.sjaife.com
error: 1
Operation not permitted
*/
2.用IP地址返回域名
用IP地址可以查询到这个iP对于的域名,需要使用的是gethostbyaddr()函数;
struct hostent *gethostbyaddr(const void *addr,socklet_t,int type);
addr:保存了ip地址的字符串
socklen_t:ip地址的长度
type:一般值为AF_INET
实例:
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
struct hostent *host;
extern int h_errno;
struct in_addr in;
char addr[] = "183.220.192.136";
if((host = gethostbyaddr(addr,sizeof(addr),AF_INET)) != NULL){
memcpy(&in,host->h_addr_list,4);
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{
printf("IP: %s\n",addr);
printf("errno: %d\n",h_errno);
printf("%s\n",hstrerror(h_errno));
}
return 0 ;
}
三、网络IP地址的转换
网络IP地址在网络传输与计算机内部的自己存储方式是不同的,需要用相关函数对网络IP地址进行转换。
1.将网络地址转换成长整型数
函数inet_addr()可以将网络IP地址转换为十进制的长整型数:
long inet_addr(char *cp);
实例:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){
char cp[] = "192.168.1.1";
printf("ld\n",inet_addr(cp));
}
输出结果为:16885952
2.将长整型IP地址转换为网络地址
inet_ntoa()可以将一个IP类型的结构体转换成点分十进制的网络IP地址。
char *inet_ntoa(struct in_addr in);
实例:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){
struct in_addr in;
in.s_addr = 16885952;
printf("%s\n",inet_ntoa(in));
}
输出结果:192.168.1.1
四、错误处理
在网络程序中,可以使用下面的语句来捕获发生错误的编号。
extern int h_error;
捕获这个错误编号后,可以用hstrerror()函数输出这个错误信息:
char *hstrerror(int err);
实例:
#include<stdio.h>
#include<netdb.h>
int main(){
int i;
for(i = 0 ; i < 10 ; i++){
printf("%d : %s \n",i,hstrerror(i));
}
}
输出结果:
0 : Resolver Error 0 (no error)
1 : Unknown host
2 : Host name lookup failure
3 : Unknown server error
4 : No address associated with name
5 : Unknown resolver error