栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux网络编程2——socket编程

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux网络编程2——socket编程

学习视频链接

黑马程序员-Linux网络编程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iJ411S7UA?p=17

一、网络套接字(英文socket) 1.1 原理图

虚线方框表示的是一个套接字

1.2 简介

在通信过程中,套接字一定是成对出现的

二、网络字节序 2.1 大小端法

小端法:(pc本地存储) 高位存高地址。地位存低地址。int a = 0x12345678

大端法:(网络存储) 高位存低地址。地位存高地址

计算机采用小端法

网络采用大端法

2.2 函数介绍

1、函数

为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和本地字节序的转换

#include 

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

htonl ——> 本地字节序 ——> 网络字节序 (IP)

htons ——> 本地字节序 ——> 网络字节序 (port)

ntohl ——> 网络字节序 ——> 本地字节序 (IP)

ntohs ——> 网络字节序 ——> 本地字节序 (port)

2、对上面函数进行封装

192.168.1.11 本质是一个 string,把这个转换成 int 整数,再调用 htonl 转换成网络字节序的整个流程可以用下面的函数代替

#include 

int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

该函数支持 IPv4 和 IPv6 

三、IP地址转换函数 3.1 inet_pton

1、作用

本地字节序 (string IP) ——> 网路字节序

2、int inet_pton(int af, const char *src, void *dst);

(1) 传入参数

af:AF_INET、AF_INET6 

src:传入,IP 地址(点分十进制)

dst:传出,转换后的网络字节序的 IP 地址

(2) 返回值:

成功:1

异常:0,说明 src 指向的不是一个有效的 ip 地址

失败:-1

3.2 inet_ntop

1、作用

网络字节序 ——> 本地字节序 (string IP)

2、const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

(1) 传入参数

af:AF_INET、AF_INET6

src:网络字节序 IP 地址

dst:本地字节序 (string IP)

size:dst 的大小

(2) 返回值

成功:dst

失败:NULL

四、sockaddr 数据结构 4.1 简介

strcut sockaddr 很多网络编程函数诞生早于 IPv4 协议,那时候都使用的是 sockaddr 结构体,为了向前兼容,现在 sockaddr 退化成了 (void*) 的作用,传递一个地址给函数,至于这个函数是sockaddr_in 还是 sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型

通过 man 7 ip 查看

4.2 新建一个sockaddr

struct sockaddr_in addr;

addr.sin_family = AF_INET/AF _INET6;  // 选择 ip 类型 ipv4、ipv6

addr.sin_port = htons(9527);  // 选择端口号

// 写法1:选择 ip 地址

int dst;

inet_pton(AF_INET, "192.157.22.45", (void*)&dst);

addr.sin_addr.s_addr = dst;

// 写法2:选择 ip 地址

addr.sin_addr.s_addr = htonl(INADDR_ ANY);   // 取出系统中有效的任意IP地址,二进制类型(可以转换成字节序)

bind(fd, (struct sockaddr *)&addr, size);

五、socket流程和相关函数 5.1 流程图

server: 

1、socket() 创建socket
2、bind()绑定服务器地址结构
3、listen()监听上限
4、accept()阻塞监听客户端连接
5、read()读socket获取客户端数据
6、小写—>大写toupper()
7、write(fd)
8、close()

client:

1、socket()创建socket
2、connect()与服务器建立连接
3、write()写数据到socket
4、read()读转换后的数据
5、显示读取结果
6、close()

5.2 socket函数

1、作用

创建一个套接字

2、#include

int socket(int domain, int type, int protocol);

(1) 参数

domain:AF_INET、AF_INET6、AF_UNIX(ip地址协议:ipv4、ipv6、本地套接字)

type:SOCK_STREAM、SOCK_DGRAM(数据传输协议:流式协议、报式协议)

protocol:0(选择报式协议套接字)

(2) 返回值

成功:新套接字所对应文件描述符

失败:-1 errno

5.3 bind函数

1、作用

给 socket 绑定一个地址结构 (IP +port)

2、#include

#include

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

(1) 参数

sockfd:socket 函数返回值

        addr.sin_family = AF_INET;

        addr.sin_port = htons(8888);

        addr.sin_addr.s_addr = htonl(INADDR_ANY);

addr:传入参数(struct sockaddr *)&addr

addrlen:sizeof(addr) 地址结构的大小

(2) 返回值

成功:0

失败:-1 errno

5.4 listen函数

1、作用

设置同时与服务器建立连接的上限数 (同时进行 3 次握手的客户端数量)

2、int listen(int sockfd, int backlog);

(1) 参数

sockfd:socket 函数返回值

backlog:上限数值。最大值 128

(2) 返回值:

成功:0

失败:-1 errno

5.5 accept函数

1、作用

阻塞等待客户端建立连接,成功的话,返回一个与客户端成功连接的 socket 文件描述符

2、int accept(int sockfd, struct sockaddr *addr,socklen_t *addrlen);

(1) 参数

sockfd:socket 函数返回值

addr:传出参数。成功与服务器建立连接的那个客户端的地址结构 (IP + port)

        socklen_t clit_addr_len = sizeof(addr);

addrlen:传入传出。&clit_addr_len  入:addr 的大小。 出:客户端 addr 实际大小

(2) 返回值

成功:能与服务器进行数据通信的 socket 对应的文件描述

失败:-1  errno

5.6 connect函数

1、作用

使用现有的 socket 与服务器建立连接

2、int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

(1) 参数

sockfd:socket 函数返回值

addr:传入参数。服务器的地址结构

(2) 返回值:

成功:0

失败:-1 errno

如果不适用 bind 绑定客户端地址结构,采用 "隐式绑定"

六、server的实现 6.1 建立C语言项目

6.2 代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERV_PORT 9527

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main(int argc, char *argv[])
{
    int lfd = 0, cfd = 0;
    int ret;
    char buf[BUFSIZ];  // BUFSIZ 系统自带的宏,大小 4096

    struct sockaddr_in serv_addr, clit_addr;
    socklen_t clit_addr_len;

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // AF_INET:     ipv4
    // SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    if (lfd == -1) {
        sys_err("socket error");
    }

    // 给socket绑定地址
    bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    // 最大连接数
    listen(lfd, 128);

    clit_addr_len = sizeof(clit_addr);

    cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
    if (cfd == -1) {
        sys_err("accept error");
    }

    while (1) {
        ret = read(cfd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, ret);

        for (int i = 0; i < ret; i++) {
            buf[i] = toupper(buf[i]);
        }

        write(cfd, buf, ret);  // 写回到客户端
    }
    close(lfd);
    close(cfd);

    return 0;
}

6.3 测试运行

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/881414.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号