0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

TCP/UDP网络编程的基础知识合集1

jf_78858299 来源:百问科技 作者:韦东山 2023-05-18 17:31 次阅读

本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信

内容目录

  1. 目标

    2.Linux网络编程基础

    2.1 嵌套字2.2 端口

    2.3 网络地址

    2.3.1 网络地址的格式

    2.3.2 网络地址的转换

    2.4 字节序

    3.TCP

    3.1 TCP流程图

    3.2 TCP步骤分析

    3.3 TCP完整代码

    3.4 测试结果

    4.UDP

    4.1 UDP流程图

    4.2 UDP步骤分析

    4.3 UDP完整代码

    4.4 测试结果

1. 目标

实现让两个设备通过网络传输数据,比如开发板和Linux主机之间传数据,

以后就可以实现开发板通过网络上报数据或者 主机通过网络控制开发板

此外,暂时不想关心具体的网络模型,更注重于网络相关函数的直接使用。

2.Linux网络编程基础

2.1 嵌套字

多个TCP连接或者多个应用程序进程 可能需要同一个TCP端口传输数据。

为了区分不同应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP交互提供了称为 嵌套字(Socket)接口

Linux中的网络编程正是通过Socket接口实现的,Socket是一种文件描述符。

常用的TCP/IP有以下三种类型的嵌套字:

  • 流式嵌套字(SOCK_STREAM)

    用于提供面向连接的、可靠的数据传输服务,即使用TCP进行传输。

  • 数据报嵌套字(SOCK_DGRAM

    用于提供无连接的服务,即使用UDP进行传输。

  • 原始嵌套字(SOCK_RAW)

    可以读写内核没有处理的IP数据报,而流式嵌套字只能读取TCP的数据,数据报嵌套字只能读取UDP的数据。

因此,如果要访问其它协议发送的数据必须使用原始嵌套字,它允许对底层协议(如IP或ICMP)直接访问。

2.2 端口

TCP/IP协议中的端口,端口号的范围从0~65535。

一类是由互联网指派名字和号码公司ICANN负责分配给一些常用的应用程序固定使用的“周知的端口”,其值一般为0~1023。例如http的端口号是80,FTP为21,SSH为22,Telnet为23等。

还有一类是用户自己定义的,通常是大于1024的整型值。

2.3 网络地址

网络通信,归根到底还是进程间的通信(不同计算机上的进程间通信)。

在网络中,每一个节点(计算机或路由)都有一个网络地址,如192.168.1.4,也就是IP地址。

两个进程通信时,首先要确定各自所在的网络节点的网络地址。

但是,网络地址只能确定进程所在的计算机,而一台计算机上很可能同时运行着多个进程,所以仅凭网络地址还不能确定到底是和网络中的哪一个进程进行通信,因此套接口中还需要包括其他的信息,也就是端口号(PORT)。

在一台计算机中,一个端口号一次只能分配给一个进程,也就是说,在一台计算机中,端口号和进程之间是一一对应关系。

所以, 使用端口号和网络地址的组合可以唯一的确定整个网络中的一个网络进程

例如,如网络中某一台计算机的IP为192.168.1.4,操作系统分配给计算机中某一应用程序进程的端口号为1500,则此时192.168.1.4 1500就构成了一个套接口。

2.3.1 网络地址的格式

在Socket程序设计中,struct sockaddr用于记录网络地址,其格式如下:

1struct sockaddr
2{
3     unsigned short sa_family; /*协议族,采用AF_XXX的形式,例如AF_INET(IPv4协议族)*/
4     char sa_data[14]; /*14字节的协议地址,包含该socket的IP地址和端口号。*/
5};

但在实际编程中,并不针对sockaddr数据结构进行操作,而是用与其等价的sockaddr_in数据结构:

1struct sockaddr_in
2{
3     short int sa_family; /*地址族*/
4     unsigned short int sin_port; /*端口号*/
5     struct in_addr sin_addr; /*IP地址*/
6     unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
7};

2.3.2 网络地址的转换

IP地址通常用数字加点(如192.168.1.4)表示,而在struct in_addr中使用的式32位整数表示。因此,Linux提供如下函数进行两者之间的转换:

  • inet_aton()函数:

所需要头文件

#include

#include

#include

函数格式

int inet_aton(const char *cp, struct in_addr *inp);

函数功能

将a.b.c.d字符串形式的IP地址转换成32位网络序号IP地址;

*cp:存放字符串形式的IP地址的指针

*inp:存放32位的网络序号IP地址

返回值

转换成功,返回非0,否则返回0;

  • inet_ntoa()函数:客户机端:

所需要头文件

#include

#include

#include

函数格式

char *inet_ntoa(struct in_addr in);

函数功能

将32位网络序号IP地址转换成a.b.c.d字符串形式的IP地址;

in:Internet主机地址的结构

返回值

转换成功,返回一个字符指针,否则返回NULL;

2.4 字节序

不同的CPU采用对变量的字节存储顺序可能不同。

常用的X86结构是小端模式,很多的ARMDSP都为小端模式,即内存的低地址存储数据的低字节,高地址存储数据的高字节。

KEIL C51则为大端模式,内存的高地址存储数据的低字节,低地址存储数据高字节。

对于网络传输来说,数据顺序必须是一致的,网络字节顺序采用大端字节序方式。

下面是四个常用的转换函数:

主机转网络:

  • htons()函数:

所需要头文件

#include

函数格式

unsigned short int htons(unsigned short int hostshort)

函数功能

参数指定的16位主机(host)字符顺序转换成网络(net)字符顺序;

hostshort:待转换的16位主机字符顺序数

返回值

返回对应的网络字符顺序数;

  • htonl()函数:

所需要头文件

#include

函数格式

unsigned long int htons(unsigned long int hostlong)

函数功能

将参数指定的32位主机(host)字符顺序转换成网络(net)字符顺序;

hostlong:待转换的32位主机字符顺序数

返回值

返回对应的网络字符顺序数;


网络转主机:

  • ntohs()函数:

所需要头文件

#include

函数格式

unsigned short int ntohs(unsigned short int netshort)

函数功能

将参数指定的16位网络(net)字符顺序转换成主机(host)字符顺序;

netshort:待转换的16位网络字符顺序数

返回值

返回对应的主机字符顺序数;

  • ntohl()函数:

所需要头文件

#include

函数格式

unsigned long int ntohl(unsigned long int netlong)

函数功能

将参数指定的32位网络(net)字符顺序转换成主机(host)字符顺序;

netshort:待转换的32位网络字符顺序数

返回值

返回对应的主机字符顺序数;

3.TCP

TCP有专门的传递保证机制,收到数据时会自动发送确认消息,发送方收到确认消息后才会继续发送消息,否则继续等待。

这样的好处是传输的数据是可靠的,此外它是有连接的传输,大多数网络传输都是用的TCP。

3.1 TCP流程图

3.2 TCP步骤分析

程序分为服务器端和客户机端,先从服务器端开始分析。

  • 服务器端:

    a. 创建socket

1    sock_fd = socket(AF_INET, SOCK_STREAM, 0);//AF_INET:IPV4;SOCK_STREAM:TCP
2    if (-1 == sock_fd)
3    {
4        fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
5        exit(1);
6    }

所需要头文件

#include

#include

函数格式

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

函数功能

创建一个套接字;

domain:协议域(族), 决定了套接字的地址类型 ,例如AF_INET决定了要用IPv4地址(32位)与端口号(16位)的组合。常见的协议族有: AF_INET 、AF_INET6、AF_LOCAL(或称AF_UNIX)、AF_ROUTE等;

type: 指定套接字类型SOCK_STREAM (TCP)、 SOCK_DGRAM (UDP)、SOCK_RAW

protocol:指定socket所使用的传输协议编号,通常为0

返回值

若成功,返回一个套接字描述符,否则返回-1;

Socket就是一种文件描述符,和普通的打开文件一样,需要检测其返回结果。

b. 设置socket

1    memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
2    server_addr.sin_family = AF_INET;
3    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:This machine all IP
4    server_addr.sin_port = htons(PORT_NUMBER);

设置何种协议族,设置本机IP和端口,也就有了唯一性。

c. 绑定socket

1    ret = bind(sock_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));
2    if(-1 == ret)
3    {
4        fprintf(stderr,"bind error:%s\\n\\a", strerror(errno));
5        close(sock_fd);
6        exit(1);
7    }

所需要头文件

#include

#include

函数格式

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

函数功能

把套接字绑定到本地计算机的某一个端口上;

sockfd:待绑定的套接字描述符

addr:一个struct sockaddr *指针,指定要绑定给sockfd的协议地址。内容结构由前面的协议族决定。

addrlen:地址的长度

返回值

若成功,返回0,否则返回-1,错误信息存在errno中;

d. 开始监听

1    ret = listen(sock_fd, BACKLOG);
2    if (-1 == ret)
3    {
4        fprintf(stderr,"listen error:%s\\n\\a", strerror(errno));
5        close(sock_fd);
6        exit(1);
7    }

所需要头文件

#include

#include

函数格式

int listen(int sockfd, int backlog);

函数功能

使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求,最大连接数量为backlog≤128;

sockfd:待监听的套接字描述符

backlog:最大可监听和连接的客户端数量

返回值

若成功,返回0,否则返回-1;

e. 阻塞,等待连接

1        addr_len = sizeof(struct sockaddr);
2        new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);
3        if (-1 == new_fd)
4        {
5            fprintf(stderr,"accept error:%s\\n\\a", strerror(errno));
6            close(sock_fd);
7            exit(1);
8        }
1

所需要头文件

#include

#include

函数格式

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

函数功能

接受连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求;

当accept函数接受一个连接时,会返回一个新的socket标识符,以后的数据传输和读取就要通过这个新的socket编号来处理,原来参数中的socket也可以继续使用,继续监听其它客户机的连接请求;

accept连接成功时,参数addr所指的结构体会填入所连接机器的地址数据;

sockfd:待监听的套接字描述符

addr:指向struct sockaddr的指针,用于返回客户端的协议地址

addrlen:协议地址的长度

返回值

若成功,返回一个由内核自动生成的一个全新描述字,代表与返回客户的TCP连接,否则返回-1,错误信息存在errno中;

f. 接收数据

1    recv_len = recv(new_fd, recv_buf, 999, 0);
 2    if (recv_len <= 0)
 3    {
 4        fprintf(stderr, "recv error:%s\\n\\a", strerror(errno));
 5        close(new_fd);    
 6        exit(1);
 7    }
 8    else
 9    {
10        recv_buf[recv_len] = '\\0';
11        printf("Get msg from client%d: %s\\n", client_num, recv_buf);
12    }

所需要头文件

#include

#include

函数格式

int recv(int sockfd, void *buf, size_t len, int flags);

函数功能

用新的套接字来接收远端主机传来的数据,并把数据存到由参数buf指向的内存空间;

sockfd:sockfd为前面accept的返回值,即new_fd,也就是新的套接字

buf:指明一个缓冲区

len:指明缓冲区的长度

flags:通常为0

返回值

若成功,返回接收到的字节数,另一端已关闭则返回0,否则返回-1,错误信息存在errno中;

g. 关闭socket

1    close(sock_fd);
2    exit(0);

为了应对多个连接,并保证它们之间相互独立,实际编程中往往还要加入多进程fork()。

让子进程接收数据,父进程继续监听新的连接。

  • 客户机端:

a. 创建socket

1    sock_fd = socket(AF_INET, SOCK_STREAM, 0);//AF_INET:IPV4;SOCK_STREAM:TCP
2    if (-1 == sock_fd)
3    {
4        fprintf(stderr,"socket error:%s\\n\\a", strerror(errno));
5        exit(1);
6    }

b. 设置socket

1    memset(&server_addr, 0, sizeof(struct sockaddr_in));//clear
2    server_addr.sin_family = AF_INET;
3    server_addr.sin_port = htons(PORT_NUMBER);

其中注意的是,这里设置的socket内容是指 希望连接的服务器IP和端口号信息,IP地址来自用户的输入,并转换格式得到。因此,这里的设置和服务器的设置,要保持内容上的一致。

1    ret = inet_aton(argv[1], &server_addr.sin_addr);
2    if(0 == ret)
3    {
4        fprintf(stderr,"server_ip error.\\n");
5        close(sock_fd);
6        exit(1);
7    }

c. 连接

1    ret = connect(sock_fd, (const struct sockaddr *)&server_addr, sizeof(struct sockaddr));    
2    if (-1 == ret)
3    {
4        fprintf(stderr,"connect error:%s\\n\\a", strerror(errno));
5        close(sock_fd);
6        exit(1);
7    }
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 主机
    +关注

    关注

    0

    文章

    897

    浏览量

    34609
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1272

    浏览量

    78299
  • UDP
    UDP
    +关注

    关注

    0

    文章

    311

    浏览量

    33621
  • 网络通信
    +关注

    关注

    4

    文章

    729

    浏览量

    29548
  • 网络编程
    +关注

    关注

    0

    文章

    64

    浏览量

    9981
收藏 人收藏

    评论

    相关推荐

    第12章 TCP传输控制协议基础知识

    知识点主要整理自网络)12.1 初学者重要提示12.2 TCP基础知识参考资料12.3 TCP基础知识
    发表于 10-30 08:51

    第16章 UDP用户数据报协议基础知识

    ) 16.1 初学者重要提示 16.2 UDP基础知识参考资料 16.3 UDP基础知识点 16.4 TCP
    发表于 11-02 17:27

    第25章 DHCP动态主机配置协议基础知识

    。(本章的知识点主要整理自网络) 25.1 初学者重要提示 25.2 DHCP基础知识参考资料 25.3 DHCP基础知识点25.4 DHCP函数 25.5总结
    发表于 11-20 14:55

    第27章 DNS域名系统基础知识

    转最新网络教程本章节为大家讲解DNS(Domain Name System,域名系统),通过前面章节对TCPUDP的学习,需要大家对DNS也有个基础的认识。(本章的知识点主要整理自
    发表于 11-23 15:50

    网络协议基础知识推荐

    目录一、基础协议1网络分层模型2、协议划分3、重点解析1TCP/IP和UDP协议2)HTTP和HTTPS协议3)WS和WSS协议4)SS
    发表于 07-02 06:56

    TCP(IP)协议与网络编程

    网络编程基础知识--TCP(IP)协议与网络编程
    发表于 09-01 15:01 0次下载

    TCP-IP_Socket网络编程

    网络编程基础知识--TCP-IP_Socket网络编程
    发表于 09-01 15:01 0次下载

    TCP协议基础知识

    TCP 是互联网核心协议之一,本文介绍它的基础知识
    的头像 发表于 10-16 10:29 3401次阅读
    <b class='flag-5'>TCP</b>协议<b class='flag-5'>基础知识</b>

    TCP UDPSocket调试工具应用程序和GPRS DTU数传应用的基础知识合集

    本文档的主要内容详细介绍的是TCP UDPSocket调试工具应用程序和GPRS DTU数传应用的基础知识合集
    发表于 11-14 17:41 12次下载
    <b class='flag-5'>TCP</b> UDPSocket调试工具应用程序和GPRS DTU数传应用的<b class='flag-5'>基础知识</b><b class='flag-5'>合集</b>

    电力基础知识合集

    电力基础知识合集
    发表于 03-14 16:35 0次下载

    基于Socket的UDPTCP编程解析 1

    TCP(传输控制协议)和UDP(用户数据报协议是网络体系结TCP/IP模型中传输层一层中的两个不同的通信协议。 TCP:传输控制协议,
    的头像 发表于 05-18 17:22 731次阅读
    基于Socket的<b class='flag-5'>UDP</b>和<b class='flag-5'>TCP</b><b class='flag-5'>编程</b>解析 1

    基于Socket的UDPTCP编程解析 2

    TCP(传输控制协议)和UDP(用户数据报协议是网络体系结TCP/IP模型中传输层一层中的两个不同的通信协议。 TCP:传输控制协议,
    的头像 发表于 05-18 17:22 464次阅读
    基于Socket的<b class='flag-5'>UDP</b>和<b class='flag-5'>TCP</b><b class='flag-5'>编程</b>解析 2

    TCP/UDP网络编程基础知识合集2

    本文主要记录TCP/UDP网络编程基础知识,采用TCP/U
    的头像 发表于 05-18 17:31 456次阅读

    TCP/UDP网络编程基础知识合集3

    本文主要记录TCP/UDP网络编程基础知识,采用TCP/U
    的头像 发表于 05-18 17:31 574次阅读
    <b class='flag-5'>TCP</b>/<b class='flag-5'>UDP</b><b class='flag-5'>网络</b><b class='flag-5'>编程</b>的<b class='flag-5'>基础知识</b><b class='flag-5'>合集</b>3

    TCPUDP的基本区别

    顺序,UDP不保证 UDP应用场景: 面向数据报方式 网络数据大多为短消息 拥有大量Client 对数据安全性无特殊要求 网络负担非常重,但对响应速度要求高
    的头像 发表于 11-13 15:27 547次阅读
    <b class='flag-5'>TCP</b>与<b class='flag-5'>UDP</b>的基本区别