第五章|Linux网络编程基础API

主要函数

  • 结构体 sockaddr
    表示通用socket地址
    *结构体 sockaddr_in(in_addr) 、sockaddr_in6(in6_addr)
    ipv4、ipv6专用地址结构体

  • 函数 inet_pton
    讲字符串表示ip地址转换成网络字节序整数表示的ip地址。

  • 函数 socket
    调用系统创建socket

  • 函数 bind
    将一个socket与socket地址绑定。也称命名

  • 函数listen
    socket命名后需要创建一个监听队列以存放待处理的客户连接。

  • 函数accept
    调用listen监听队列中接受一个连接。

  • 函数connect
    客户端通过系统调用主动与服务器建立连接

  • 函数close
    关闭对应的socket

  • 函数recv、send
    tcp数据读写
    读取、写入sockfd上的数据

  • 函数recvfrom、sendto
    udp数据读写
    读取、写入sockfd上的数据

  • 函数recvmsg、sendmsg
    通用数据读写

  • 函数getsockname、getpeername
    获取sockfd对应的本端socket地址
    获取sockfd对应的远端socket地址

  • 函数getsockopt、setsockopt
    专门读取和设置socket文件描述符属性的方法

主机字节序和网络字节序

理解字节序可以参考阮一峰老师的文档:
http://www.ruanyifeng.com/blog/2016/11/byte-order.html

举例来说,数值0x2211使用两个字节储存:高位字节是0x22,低位字节是0x11

  • 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。
  • 小端字节序:低位字节在前,高位字节在后,即以0x1122形式储存。
0x1234567的大小端字节序

检查机器的字节序

#include <stdio.h>

void byteorder()
{
    union
    {
        short value;
        char union_bytes[sizeof(short)];
    } test;
    test.value = 0x0102;
    if ((test.union_bytes[0] == 1) && test.union_bytes[1] == 2)
    {
        printf("big endian\n");
    }
    else if ( (test.union_bytes[0] == 2) && (test.union_bytes[1] == 1))
    {
        printf("little endian\n");
    }
    else
    {
        printf('unknown..\n');
    }
}

int main() {
    //printf("Hello, World!\n");
    byteorder();
    return 0;
}

现在pc大多采用小端字节序,因此小端字节序又被称为主机字节序。
大端也称为网络字节序。
即使是同一台机器上的两个进程通信,也要考虑字节序的问题。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>

static bool stop = false;
//SIGTERM信号处理函数,触发时结束主程序中的循环
static void handle_term( int sig )
{
    stop = true;
}

int main( int argc, char* argv[] )
{
    signal( SIGTERM, handle_term );

    if( argc <= 3 )
    {
        printf( "usage: %s ip_address port_number backlog\n", basename( argv[0] ) );
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi( argv[2] );
    int backlog = atoi( argv[3] );

    //创建一个socket PF_INET:ipv4   SOCK_STREAM:流服务
    int sock = socket( PF_INET, SOCK_STREAM, 0 );
    //判断是否失败  失败返回-1并设置errno  成功返回socket文件描述符
    assert( sock >= 0 );

    //创建一个专用 IPV4 socket 地址
    struct sockaddr_in address;
    //bzero功能:置字节字符串address的前sizeof( address )个字节为零且包括‘\0’
    bzero( &address, sizeof( address ) );  
    address.sin_family = AF_INET;//地址组
    //inet_pton:将用字符串表示ip地址转换成网络字节序整数表示的ip地址。 成功返回1 失败返回0
    inet_pton( AF_INET, ip, &address.sin_addr );
    //小端转大端 、主机字节序转换网络字节序
    address.sin_port = htons( port );
    
    //命名socket   将address所指的地址分配给未命名的 sock 变量(文件描述符)
    int ret = bind( sock, ( struct sockaddr* )&address, sizeof( address ) );
    // bind 成功返回0 失败返回-1 并设置errno
    assert( ret != -1 );

    //监听socket sock参数:指定被监听的socket   backlog参数:提示内核监听队列的最大长度
    ret = listen( sock, backlog );
    //listen 成功返回0  失败返回-1 并设置errno
    assert( ret != -1 );

    //循环等待连接,直到有SIGTERM信号将他中断。
    while ( ! stop )
    {
        sleep( 1 );
    }

    //关闭socket
    close( sock );
    return 0;
}

在B主机

./程序名 192.168.30.109 12345 5

记得防火墙开启12345端口(如果是afw)

season@ubuntu:~$ sudo ufw allow 12345

主机A执行十次:

telnet 192.168.30.109 12345

发现执行6次后,一直处于等待中。
主机B:

netstat -nt |grep 12345

出现6(backlog值+1)个ESTABLISHED

accept用法

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


int main(int argc, char *argv[]) {
    if (argc <= 2) {
        printf("usage: %s id_address prot_number \n", basename(argv[0]));
        return 1;
    }


    const char *ip = argv[1];
    //字符串转换成整型数的一个函数
    int port = atoi(argv[2]);

    //创建一个专用 IPV4 socket 地址
    struct sockaddr_in address;
    //bzero功能:置字节字符串address的前sizeof( address )个字节为零且包括‘\0’
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;//地址组
    //inet_pton:将用字符串表示ip地址转换成网络字节序整数表示的ip地址。 成功返回1 失败返回0
    inet_pton(AF_INET, ip, &address.sin_addr);
    //小端转大端 、主机字节序转换网络字节序
    address.sin_port = htons(port);


    //创建一个socket PF_INET:ipv4   SOCK_STREAM:流服务
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    //判断是否失败  失败返回-1并设置errno  成功返回socket文件描述符
    assert(sock >= 0);

    //命名socket   将address所指的地址分配给未命名的 sock 变量(文件描述符)
    int ret = bind(sock, (struct sockaddr *) &address, sizeof(address));
    // bind 成功返回0 失败返回-1 并设置errno
    assert(ret !=-1);

    //监听socket sock参数:指定被监听的socket   backlog参数:提示内核监听队列的最大长度
    ret = listen(sock,5);
    //listen 成功返回0  失败返回-1 并设置errno
    assert(ret !=-1);

    sleep(20);

    //创建一个专用 IPV4 socket 地址
    struct sockaddr_in client;
    socklen_t client_addrlength = sizeof(client);
    int connfd = accept(sock,(
    struct sockaddr*)&client ,&client_addrlength);
    if (connfd < 0)
    {
        printf("error is :%d\n",errno);
    }
    else
    {
        char remote[INET_ADDRSTRLEN];
        printf("connected with ip: %s and port: %d \n",
               inet_ntop(AF_INET,&client.sin_addr,remote,INET_ADDRSTRLEN),ntohs(client.sin_port));
        close(connfd);
    }

    //关闭socket
    close(sock);
    return 0;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容