网络编程 lesson2 TCP基础编程

news2024/10/6 10:26:11

目录

sockt介绍

socket类型

socket所在位置

端口号(重点)

端口号作用

端口号范围

字节序(面试常见)

大端序

小端序

验证当前主机字节序

字节序转换和IP转换函数接口(常用)

TCP编程

函数接口 

socket(重点)

 bind

listen

accept(阻塞函数)

recv:能判断客户端是否中断

connect

send

练习:编写一个客户端和服务器程序,客户端发送消息,服务器接收并打印

server

client


sockt介绍

Socket是一种编程接口(API),用于在计算机网络中实现进程间的通信。它提供了一组函数,允许开发人员创建网络应用程序,通过网络传输数据并进行网络通信。

通过Socket,应用程序可以使用不同的网络协议(如TCP、UDP)进行通信,并在不同的计算机之间进行数据交换。Socket提供了一种抽象层,隐藏了底层网络细节,使开发人员能够专注于应用程序的逻辑,而不必过于关注底层网络编程细节

  1. 是一个编程接口
  2. 是一种特殊的文件描述符
  3. 不只局限于TCP和IP协议
  4. 面向连接和无连接

 总而言之,Socket提供了一种通用的网络编程接口,使开发人员能够创建网络应用程序,并实现跨计算机的数据传输和网络通信。它为开发各种类型的网络应用提供了基础设施和工具。

socket类型

流式套接字(SOCK_STREAM) TCP

特点:面向连接,可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。

数据报套接字(SOCK_DGRAM) UDP

特点:面向无连接,数据包以独立的形式发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。

原始套接字(SOCK_RAM)

特点:对较低层次协议如IP和ICMP访问。

socket所在位置

Socket通常位于操作系统网络协议栈中。具体而言,Socket位于传输层(Transport Layer)和网络层(Network Layer)之间

它是应用程序与底层网络协议之间的接口,充当了应用程序与网络之间的桥梁。

端口号(重点)

端口号作用

  • 端口号用于标识网络中特定的进程或服务,实现进程间的通信和数据交换。它是网络通信中的重要组成部分,确保数据包被正确地传递到目标进程或服务。
  • TCP的端口号与UDP端口号独立
  • 端口号用两个字节表示 2byte
  • 端口号的管理由Internet Assigned Numbers Authority(IANA,互联网编号分配机构)负责。IANA是一个全球性的组织,负责分配和管理全球互联网资源的唯一性和可用性,其中包括IP地址、域名和端口号等。

端口号范围

  1. 知名端口(Well-known Ports):范围从0到1023,用于标识特定的协议或服务。这些端口号通常与广泛使用的协议和服务相关联。如HTTP(端口号80)、FTP(端口号21)、SSH(端口号22)等。这些端口号的分配和管理由IANA直接负责。
  2. 注册端口(Registered Ports):范围从1024到49151,用于用户自定义的应用程序或服务。这些端口号可以由开发人员和组织自行申请并注册,以确保不同的应用程序之间不发生冲突。IANA维护了一个注册端口号列表,记录了已被分配的端口号及其分配给的应用程序或服务。
  3. 动态端口(Dynamic or Private Ports):范围从49152到65535,用于动态分配给客户端应用程序。当客户端应用程序需要进行网络通信时,操作系统会自动分配一个未使用的动态端口号。动态端口号的使用是临时的,通常在通信结束后被释放。

字节序(面试常见)

大端序

大端序(Big Endian):在大端序中,高位字节存储在低地址低位字节存储在高地址类似于人类读写数字的方式,从左到右依次表示更高位到更低位。例如,十六进制数0x12345678在大端序中的存储顺序为0x12 0x34 0x56 0x78。

小端序

小端序(Little Endian):在小端序中,低位字节存储在低地址,高位字节存储在高地址。与大端序相反,字节的存储顺序与数值的表示方式相同,从左到右依次表示更低位到更高位。例如,十六进制数0x12345678在小端序中的存储顺序为0x78 0x56 0x34 0x12。

验证当前主机字节序

#include <stdio.h>
union test{
    int a;
    char b;
    short c;
};
int main()
{
    int a=0x123456;
    //1.指针强转法
    char*p=(char*)&a;
    printf("%x\n",*p);//56
    printf("%x\n",*(p+1));//34
    //2.数据类型强转
    printf("%x\n",(char)a);//56
    printf("%x\n",(short)a);//3456
    //3.union共用体方法
    union test s1;
    s1.a=0x123456;
    printf("%x\n",s1.b);//56
    printf("%x",s1.c);//3456
    return 0;
}

一般主机是小端序,网络是大端序。

字节序转换和IP转换函数接口(常用)

主机字节序到网络字节序(host to network)
u_long htonl (u_long hostlong);
u_short htons (u_short short);  //掌握这个

网络字节序到主机字节序(network to host )
u_long ntohl (u_long hostlong);
u_short ntohs (u_short short);

IP转换
in_addr_t inet_addr(const char *cp); //"Internet address"的缩写 
//从人看的ip地址转为机器使用的32位无符号整数

char *inet_ntoa(struct in_addr in);//"Internet network to ASCII"的缩写 
//从机器到人

TCP编程

 注:上图主要是一种思想,实际编程思路如下函数接口

TCP服务器创建步骤:

socket:创建用于链接的套接字
bind:绑定套接字
listen:监听套接字,将主动套接字转换为被动套接字
accept:(重点:阻塞)等待客户端链接,链接成功返回一个链接套接字
recv:接收消息(根据实际情况决定顺序)
send:发送消息(根据实际情况决定顺序)
close:关闭socket和accept创建的套接字

TCP客户端创建步骤:

socket:创建用于链接的套接字
connect:(重点:阻塞)等待服务器链接
recv:接收消息(根据实际情况决定顺序)
send:发送消息(根据实际情况决定顺序)
close:关闭socket创建的套接字

函数接口 

socket(重点)

int socket(int domain, int type, int protocol);
功能:创建套接字
参数:
   domain:协议族
     AF_UNIX, AF_LOCAL  本地通信
     AF_INET            ipv4
     AF_INET6            ipv6
  type:套接字类型
     SOCK_STREAM:流式套接字
     SOCK_DGRAM:数据报套接字
  protocol:协议 - 填0 自动匹配底层 ,根据type
  系统默认自动帮助匹配对应协议
     传输层:IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP
     网络层:htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)
 返回值:
    成功 文件描述符
    失败 -1,更新errno

 bind

int bind(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);
功能:绑定   ipv4  ip和端口
参数
   sockfd:文件描述符
   addr:通用结构体,根据socket第一个参数选择的通信方式最终确定这需要真正填充传递的结构体是那个类型。强转后传参数。
   addrlen:填充的结构体的大小   
返回值:0 失败-1、更新errno

使用网络编程需要用到的结构体:

通用结构体:
struct sockaddr {
    sa_family_t sa_family;
    char        sa_data[14];
}

ipv4结构体:
struct sockaddr_in {
     sa_family_t    sin_family;  //协议族AF_INET
     in_port_t      sin_port;  //端口
     struct in_addr sin_addr;   
 };

ipv4结构体中存在一个struct in_addr 结构体:
 struct in_addr {
     uint32_t       s_addr;   //IP地址  
 };

ipv6结构体:
struct sockaddr_in6 {
    sa_family_t     sin6_family;   
    in_port_t       sin6_port;     
    uint32_t        sin6_flowinfo; 
    struct in6_addr sin6_addr;     
    uint32_t        sin6_scope_id; 
};
struct in6_addr {
    unsigned char   s6_addr[16];   
};

listen

int listen(int sockfd, int backlog);
功能:监听,将主动套接字变为被动套接字
参数:
 sockfd:套接字
 backlog:同时响应客户端请求链接的最大个数,不能写0.
  不同平台可同时链接的数不同,一般写6-8个
    (队列1:保存正在连接)
    (队列2,连接上的客户端)
   返回值:成功 0   失败-1,更新errno  

accept(阻塞函数)

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept(sockfd,NULL,NULL);
阻塞函数,阻塞等待客户端的连接请求,如果有客户端连接,
则accept()函数返回,返回一个用于通信的套接字文件;
参数:
   Sockfd :套接字
   addr: 链接客户端的ip和端口号
      如果不需要关心具体是哪一个客户端,那么可以填NULL;
   addrlen:结构体的大小
     如果不需要关心具体是哪一个客户端,那么可以填NULL;
  返回值: 
     成功:文件描述符; //用于通信
失败:-1,更新errno

recv:能判断客户端是否中断

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能: 接收数据 
参数: 
    sockfd: acceptfd ;
    buf  存放位置
    len  大小
    flags  一般填0,相当于read()函数
    MSG_DONTWAIT  非阻塞
返回值: 
   < 0  失败出错  更新errno
   ==0  表示客户端退出
   >0   成功接收的字节个数

connect

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:用于连接服务器;
参数:
     sockfd:socket函数的返回值
     addr:填充的结构体是服务器端的;
     addrlen:结构体的大小
返回值 
      -1 失败,更新errno
      正确 0 

send

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:发送数据
参数:
    sockfd:socket函数的返回值
    buf:发送内容存放的地址
    len:发送内存的长度
    flags:如果填0,相当于write();

练习:编写一个客户端和服务器程序,客户端发送消息,服务器接收并打印

server

//server
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define N 128
typedef struct msg
{
    int a;
    char buf[N];
} msg_t, *msg_p;

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket err.");
        exit(-1);
    }
    struct sockaddr_in caddr, saddr;
    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(1026);
    caddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
    {
        perror("bind err.");
        exit(-1);
    }

    if (listen(sockfd, 3) < 0)
    {
        perror("listen err.");
        exit(-1);
    }

    socklen_t len = sizeof(saddr);
    while (1)
    {
        int acceptid = accept(sockfd, (struct sockaddr *)&saddr, &len);
        if (accept < 0)
        {
            perror("accept");
            exit(-1);
        }
        printf("%d\n", ntohs(saddr.sin_port));     //打印链接端口
        printf("%s\n", inet_ntoa(saddr.sin_addr)); //打印iP
        msg_t s1;
        memset(&s1, 0, sizeof(msg_t));
        while (1)
        {
            int recvnum = recv(acceptid, &s1, sizeof(msg_t), 0);
            if (recvnum < 0)
            {
                perror("recv err.");
                exit(-1);
            }
            else if (recvnum == 0)
            {
                perror("recv err.");
                break;
            }
            printf("%s \n", s1.buf);
        }
        close(acceptid);
    }
    close(sockfd);
    return 0;
}

client

//client
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <unistd.h>

#define N 128
typedef struct msg
{
    int a;
    char buf[N];
} msg_t, *msg_p;

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket err.");
        return -1;
    }
    struct sockaddr_in caddr;
    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(1026);
    caddr.sin_addr.s_addr = INADDR_ANY;

    if (connect(sockfd, (struct sockaddr *)&caddr, sizeof(caddr)) == -1)
    {
        perror("connect err.");
        return -1;
    }
    msg_t s1;
    memset(&s1, 0, sizeof(msg_t));

    while (1)
    {
        fgets(s1.buf, sizeof(s1.buf), stdin);
        if (s1.buf[strlen(s1.buf) - 1] == '\n')
        {
            s1.buf[strlen(s1.buf) - 1] = '\0';
        }
        send(sockfd, &s1, sizeof(msg_t), 0);
    }
    close(sockfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526342.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[230517] TPO71 | 2022年托福阅读真题第5/36篇 | Minoan Palaces | 14:51~16:00+22:00~23:20

7102 Minoan Palaces 目录 7102 Minoan Palaces 正文 题目 Paragraph 1 问题 1 Paragraph 2 问题 2 Paragraph 3 问题 3 4 Paragraph 4 问题 5 6 Paragraph 5 问题 7 8 Paragraph 2-问题9 全篇-问题10 正确率&#xff1a;7/10 正文 Paragraph 1 The…

JavaScript实现输入指定行数,输出三角形的代码

以下为实现输入指定行数&#xff0c;输出三角形的程序代码和运行截图 目录 前言 一、实现输入指定行数&#xff0c;输出三角形 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b;…

HCIP周日ISIS

ISIS&#xff1a;中间系统到中间系统 ES&#xff1a;终端系统 ES-IS&#xff1a;终端系统到中间系统 ISIS是一种链路状态协议&#xff0c;使用SPF算法 早期的ISIS是基于CLNP&#xff08;无连接网络协议&#xff09;而开发的&#xff0c;为了继续追逐TCP/IP的发展&#xff0…

关于getchar的用法及实例解析

一、getchar()函数是什么&#xff1f; getchar()函数是获取一个字符。说到这里就有人问了&#xff0c;为什么他的返回类型是int&#xff1f; 因为实际上EOFend of file&#xff08;-1&#xff09;&#xff0c;EOF实际上就等于-1。当你返回失败的时候返回的是-1&#xff0c;所以…

计算机网络(四上)——网络层!!!重中之重

先来个整章的大框架&#xff0c;看起来也没有多少东西&#xff08;bushi&#xff09;。 这篇文章&#xff0c;就先写 一、网络层的功能 互联网在网络层的设计思路是&#xff0c;向上只提供简单灵活的、无连接的、尽最大努力交付的数据报服务 1.1.异构网络互联 1.网络互联是…

Springboot +Flowable,流程表单应用之动态表单

一.简介 整体上来说&#xff0c;我们可以将Flowable 的表单分为三种不同的类型&#xff1a; 动态表单 这种表单定义方式我们可以配置表单中每一个字段的可读性、可写性、是否必填等信息&#xff0c;不过不能定义完整的表单页面。外置表单 外置表单我们只需要定义一下表单的 k…

kafka 从入门到精通

kafka 从入门到精通 安装 zookeeper模式 创建软件目录 mkdir /opt/soft cd /opt/soft下载 wget https://downloads.apache.org/kafka/3.4.0/kafka_2.13-3.4.0.tgz解压 tar -zxvf kafka_2.13-3.4.0.tgz 修改目录名称 mv kafka_2.13-3.4.0 kafka配置环境变量 vim /etc/pr…

C51基础之单片机编程中通用指针和定向指针

通用指针和定向指针 参考资料&#xff1a;Keil > Help > uVision Help > Cx51 Compiler User’s Guide > Language Extensions > Pointers 一、Cx51指针的几种用法 int *ptr; /* 指向&#xff1a;任意空间的int变量&#xff0c; 存储在&…

什么是Java中的finalize()方法?它有什么作用

在Java中&#xff0c;finalize()方法是一个由Object类定义的方法&#xff0c;用于在对象被垃圾回收器回收之前执行一些清理工作。finalize()方法是一个被保护的方法&#xff0c;可以被子类重写&#xff0c;但是通常情况下不需要显式地调用该方法。 finalize()方法的作用 在Jav…

MYSQL原理、设计与应用

概述 数据库(Database&#xff0c;DB)是按照数据结构来组织、存储和管理数据的仓库&#xff0c;其本身可被看作电子化的文件柜&#xff0c;用户可以对文件中的数据进行增删改查等操作。 数据库系统是指在计算机系统中引入数据库后的系统&#xff0c;除了数据库&#xff0c;还…

首次开通社交账号亲自招聘人才 周星驰都在关注的Web3 你知道是什么吗?

60岁的“星爷”周星驰要进军元宇宙了&#xff1f; 谁能想到&#xff0c;向来低调的他首次注册社交账号&#xff0c;竟是为了发布一条招人信息&#xff0c;挑选的还不是新片男女主角&#xff0c;而是Web3人才&#xff0c;一脚跨界到了互联网科技领域。 今天一整天&#xff0c;…

2022-2023 年度广东省职业院校学生专业技能大赛中职组“网络安全”赛项竞赛任务书(样题)

2022-2023 年度广东省职业院校学生专业技能大赛中职组“网络安全”赛项竞赛任务书&#xff08;样题&#xff09; 一、竞赛时间 总计&#xff1a;210 分钟 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A 模块 A-1 登录安全加固 90 分钟 200…

node笔记_express结合formidable实现前后端的文件上传

文章目录 ⭐前言⭐安装http请求的文件解析依赖库&#x1f496; 安装 formidable&#x1f496; node formidable接受formData上传参数 ⭐上传的页面搭建&#x1f496; vue2 element upload&#x1f496; node 渲染 上传文件 ⭐后端生成api上传文件到指定目录&#x1f496;完整的…

【Spring篇】Spring入门案例

&#x1f353;系列专栏:Spring系列 &#x1f349;个人主页:个人主页 目录 一、IOC入门案例 1.入门案例思路分析 2.入门案例代码实现 二、DI入门案例 1.入门案例思路分析 2.入门案例代码实现 三、图书推荐 介绍完Spring的核心概念后&#xff0c;接下来我们得思考一个问题…

2023年安徽省中职网络安全跨站脚本攻击

B-4:跨站脚本攻击 任务环境说明: √ 服务器场景:Server2125(关闭链接) √ 服务器场景操作系统:未知 √ 用户名:未知 密码:未知 1.访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交; 通过尝试知道这里存在xss漏洞

【CVE-2022-26134】Confluence OGNL RCE 漏洞

漏洞描述 远程攻击者在未经身份验证的情况下&#xff0c;可构造OGNL表达式进行注入&#xff0c;实现在Confluence Server或Data Center上执行任意代码。 影响版本 Confluence Server and Data Center > 1.3.0 Confluence Server and Data Center < 7.4.17 Confluenc…

九头蛇3389远程爆破

1.初学KALI hydra&#xff08;海德拉&#xff09;。 实验环境&#xff1a;VM16,虚拟机两台&#xff0c;Windows10系统&#xff0c;KALI系统&#xff0c;用nmap查看目标端口是否开放。 2.在KALI虚拟机上面使用命令nmap查看WIN10的3389端口是否打开。 3.在KALI虚拟机上面建立用…

Java sdk使用加载账户私钥调用合约

Java sdk使用加载账户私钥调用合约 1.智能合约案例 1.2 智能合约的流程 1.2 智能合约详细代码 实现了一个简单的商店功能。它定义了三个结构体&#xff1a;用户、商家和商品&#xff0c;以及对应的映射关系。它提供了一些方法用于注册用户和商家&#xff0c;创建商品&#x…

MVC模式和三层架构

MVC模式和三层架构 MVC模式三层架构MVC与三层架构的联系MVC与三层架构的异同 MVC模式 MVC&#xff08;Model View Controller&#xff09;是软件工程中的一种软件设计模式&#xff0c;它把软件系统分为模型、视图和控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方…

路由器+Gdbserver+IDA Pro远程调试

最近在复现路由器漏洞&#xff0c;也踩了不少坑&#xff0c;记录一下&#xff0c;希望能对需要的人有一些帮助。使用的路由器型号为RT-AC68U&#xff0c;ARM架构&#xff0c;小端序&#xff0c;Linux内核版本2.6.36&#xff0c;很老&#xff0c;主要的时间也花费在找能支持这个…