linux: 初试网络编程

socket信息数据结构

#include <netinet/in.h>

struct sockaddr
{
    unsigned short sa_family;      /*地址族*/
    char sa_data[14];              /*14字节的协议地址,包含该socket的IP地址和端口号。*/
};
struct sockaddr_in
{
    short int sa_family;           /*地址族*/
    unsigned short int sin_port;   /*端口号*/
    struct in_addr sin_addr;       /*IP地址*/
    unsigned char sin_zero[8];     /*填充0 以保持与struct sockaddr同样大小*/
};
struct in_addr
{
        unsigned long int  s_addr;    /* 32位IPv4地址,网络字节序 */
};
#include <netinet/in.h>

tips
sa_family:
AF_INET   -> IPv4协议
AF_INET6  -> IPv6协议

注意

结构体struct in_addr中存放的s_addr,是无符号整型数。实际上32位IPv4地址为点分十进制,每个字节的范围均为0-255,只要高字节大于等于128,那么这个整型数必然为负数,只不过我们这边仅仅关心ip每一位的存储情况,因此此处可以使用无符号数进行存储。

函数原型1

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

       int inet_aton(const char *cp, struct in_addr *inp);/* 注意,参数inp为传出参数 */
       char *inet_ntoa(struct in_addr in);

实际上,我们在上篇文章中实现的三个函数是有系统函数可以直接调用的。我们的my_atoh,my_hton合并为系统函数inet_aton,而my_ntoa即为系统函数inet_ntoa。

举例1

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

int main(int argc, char *argv[])
{
    char ip_buf[] = "180.97.33.107";
    struct in_addr my_addr;
    inet_aton(ip_buf,&my_addr);
    printf("ip : %s \n", ip_buf);
    printf("net: %x \n", my_addr.s_addr);
    return 0;
}

运行结果

[[email protected] 0827]$ gcc -o test test.c -Wall
[[email protected] 0827]$ ./test
ip : 180.97.33.107
net: 6b2161b4
照理,网络字节序是大端存储,应该返回0xb461216b。实际上调用系统函数inet_aton后,就直接在变量my_addr.s_addr的实际内存空间中以二进制形式写入了0xb461216b(其实用位运算,就可以直接操作二进制位,上篇博文有具体实现)。之所以运行结果是0x6b2161b4,是因为我们的主机是小端存储,用printf显示结果是先取低字节。

举例2

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

int main(int argc, char *argv[])
{
    struct in_addr my_addr;
    my_addr.s_addr = 0xb461216b;
    printf("net: %x \n", my_addr.s_addr);
    printf("ip : %s \n", inet_ntoa(my_addr));
    return 0;
}

运行结果
[[email protected] 0827]$ gcc -o test1 test1.c -Wall
[[email protected] 0827]$ ./test1
net: b461216b
ip : 107.33.97.180
照理,ip应该输出的是180.97.33.107。其实道理很简单,我们的主机是小端模式存储,而网络字节序是大端模式,当我们把0xb461216b赋值给my_addr.s_addr 时,实际上在内存中存储形式是0x6b2161b4,而inet_ntoa的具体实现时通过位运算直接操纵二进制位的,因此结果就自然输出107.33.97.180。

函数原型2

SYNOPSIS
       #include <netdb.h>
       struct hostent *gethostbyname(const char *name);

The hostent structure is defined in <netdb.h> as follows:

           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 */
           }
           #define h_addr h_addr_list[0] /* for backward compatibility */

       The members of the hostent structure are:

       h_name The official name of the host.

       h_aliases
              An array of alternative names for the host, terminated by a NULL
              pointer.

       h_addrtype
              The type of address; always AF_INET or AF_INET6 at present.

       h_length
              The length of the address in bytes.

       h_addr_list
              An  array of pointers to network addresses for the host (in net-
              work byte order), terminated by a NULL pointer.

       h_addr The first address in h_addr_list for backward compatibility.

代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char* argv[])// exe hostname
{
    struct hostent* p ;
    p = gethostbyname(argv[1]) ;
    /*
    struct hostent {
        char  *h_name;
        char **h_aliases;
        int    h_addrtype;
        int    h_length;
        char **h_addr_list;
    }
#define h_addr h_addr_list[0]
 */
    printf("host name: %s \n", p ->h_name);

    int index ;
    char** pp  = p -> h_aliases ;
    for(index = 0 ; pp[index] != NULL; index ++ )
    {
        printf("alias : %s \n", pp[index]);
    }

    printf("ip type : %d\n", p ->h_addrtype);

    printf("addr len : %d \n", p ->h_length);

    pp = p ->h_addr_list ;
    for(index = 0; pp[index] != NULL ; index ++)
    {
        /* 由于h_addr_list是一个字符串指针数组,数组中存放的指针指向一个网络字节序
            但是系统函数inet_ntoa需要传入的参数是一个结构体,因此需要进行转换。
            pp[index]是一个char*类型的指针,先将其转换为struct in_addr*类型的指针,
            接着去引用,即得到结构体。                                                 */
        printf("ip : %s \n", inet_ntoa( *(struct in_addr *)pp[index] ) );
    }

    return 0 ;
}

运行结果

[[email protected] 0827]$ gcc -o myhost my_host.c -Wall
[[email protected] 0827]$ ./myhost www.baidu.com
host name: www.a.shifen.com
alias : www.baidu.com
ip type : 2
addr len : 4
ip : 180.97.33.107
ip : 180.97.33.108

干货

某年腾讯面试题:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a = 0x61;//97    内存中的情况是:小端 61 00 00 00 如果是大端机 00 00 00 61 两种情况
    printf("%x\n",(char*)(&a)[0]);  把&a转化为char*是为了只指向一个字节 int*指向的是4个字节
}

结果输出61,说明是小端机,先存低字节。

总结

切记系统函数无论inet_aton还是inet_ntoa,都是直接以位运算形式实现的,因此其关注的是数据在内存中实际的二进制存储形式。

时间: 2024-10-08 10:44:04

linux: 初试网络编程的相关文章

linux socket网络编程 常用函数及头文件

转自:http://blog.chinaunix.net/u3/102500/showart_2065640.html 一 三种类型的套接字: 1.流式套接字(SOCKET_STREAM) 提供面向连接的可靠的数据传输服务.数据被看作是字节流,无长度限制.例如FTP协议就采用这种. 2.数据报式套接字(SOCKET_DGRAM) 提供无连接的数据传输服务,不保证可靠性. 3.原始式套接字(SOCKET_RAW) 该接口允许对较低层次协议,如IP,ICMP直接访问. 二 基本套接字系统调有有如下一

linux c 网络编程:用域名获取IP地址或者用IP获取域名 网络地址转换成整型 主机字符顺序与网络字节顺序的转换

用域名获取IP地址或者用IP获取域名 #include<stdio.h> #include<sys/socket.h> #include<netdb.h> int main(int argc,char **aggv) { struct hostent *host; char hostname[]="www.163.com"; char hostname2[]="www.baidu.com"; struct in_addr in;

【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)

RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [实验目的] 1.熟练掌握线程的创建与终止方法: 2.熟练掌握线程间通信同步方法: 3.应用套接字函数完成多线程服务器,实现服务器与客户端的信息交互. [实验内容] 通过一个服务器实现最多5个客户之间的信息群发. 服务器显示客户的登录与退出: 客户连接后首先发送客户名称,之后发送群聊信息: 客户输入bye代表退

Linux Socket 网络编程

Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后,过段时间不看,重新拾起这些知识的时候又要从头开始,所以,在这里做个笔记也算是做个模板,以后可以直接从某一个阶段开始接着玩... 1. socket套接字介绍 socket机制其实就是包括socket, bind, listen, connect, accept等函数的方法,其通过指定的函数实现不同

Linux C 网络编程之初探

下面的一幅图是取自<UNIX网络编程卷一>,这个简单的C/S程序的框架 Service端程序 #include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <sys/socket.h> #include <linux/in.h> #include <string.h> int main() { int sfp,nfp; /* 定义两个描述符 *

Linux高级网络编程系列教程

一.网络应用层编程 1.Linux网络编程01--网络协议入门 2.Linux网络编程02--无连接和面向连接的区别 3.Linux网络编程03--字节序和地址转换 4.Linux网络编程04--套接字 5.Linux网络编程05--C/S与B/S架构的区别 6.Linux网络编程06--UDP协议编程 7.Linux网络编程07--广播(即将更新) 8.Linux网络编程08--多播 9.Linux网络编程09--TCP编程(即将更新) 10.Linux网络编程10--并发服务器(即将更新)

linux中网络编程&lt;1&gt;

1 网络编程API (1)网络层的ip地址可以唯一标识网络中的主机,传输层通过协议+端口唯一标识主机中的应用程序.这样以来使用三元组(地址,协议,端口)标识网络的进程. (2)socket--->插槽(低俗的哈哈哈哈),看作文件描述符,Linux基本哲学一切皆文件,那么是不是也可以读写关闭这样的习惯性操作呢.对了,差不多的啦. (3)来看看tcp交互流程 ok具体看看各个函数 第一个:int socket(int domain,int type,int protocol) 参数介绍: domai

linux下网络编程学习——入门实例ZZ

http://www.cppblog.com/cuijixin/archive/2008/03/14/44480.html 是不是还对用c怎么实现网络编程感到神秘莫测阿,我们这里就要撕开它神秘的面纱,呵呵. 一起来: 诶,不要着急,我们先来介绍一些网络程序的主要执行过程,主要是便于大家更好的理解下面的程序实例哦 : 1)系统启动服务器执行.服务器完成一些初始化操作,然后进入睡眠状态,等待客户机请求.2)在网络的某台机器上,用户执行客户机程序3)客户机进行与服务器进程建立一条连接4)连接建立后,客

linux socket网络编程详解

一.系统调用和应用编程接口 在讨论网络通信之前, 首先明确两个概念:系统调用(system call) 和 应用编程接口(Application Programming Interface,API). 操作系统使用 系统调用 机制来实现 在应用程序 与 操作系统 之间进行控制权传递. 当某个应用进程启动了系统调用时,控制权就从应用程序传递给操作系统.操作系统执行某个内部过程之后,把控制权返回给应用程序. 对程序员来说,每一个系统调用和一般程序设计中的函数调用非常相似,只是系统调用是将控制权传递给