linux基础操作之8.套接字网络通讯tcp/udp

2023-05-16

导:网络套接字编程-TCP/UDP开发实例

百科资料:http://www.baike.com/wiki/%E5%A5%97%E6%8E%A5%E5%AD%97

 

1.TCP通讯实例=====================================================================

    TCP 是一种面向连接的、可靠的、基于 IP 的传输层协议。通过 TCP 可以保证我们传送的数据的正确性。

    (1)通讯流程梳理

Linux 下网络通信程序基本上都是采用 socket 的方式。socket 起源于 Unix,而Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开 open->读写 read/write->关闭 close”模式来操作。Socket 就是该模式的一个实现,socket 即是一种特殊的文件,一些socket 函数就是对其进行的操作(开/关/读/写/建)。说白了 socket 是应用程序与 TCP/IP协议族通信的中间软件抽象层,它是一组接口。    

    (2)代码分析

                              服务器端:SBLARWRC

#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main()
{
	int sfp, nfp, num = 0;
	struct sockaddr_in s_add,c_add;
	int sin_size;
	unsigned short portnum=0x8888;//端口1对1
	char buffer[100] = {0};
	printf("Hello,welcome to my server !\r\n");

	sfp = socket(AF_INET, SOCK_STREAM, 0);		//1.s-调用 socket 函数创建一个套接字
	if(-1 == sfp)
	{
			printf("socket fail ! \r\n");
			return -1;
	}
	printf("socket ok !\r\n");
	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;使用 IPv4 协议
	s_add.sin_addr.s_addr=htonl(INADDR_ANY);允许任何地址
	s_add.sin_port=htons(portnum);设置端口号
							//2.b-用bind 绑定函数,使用的是 IPv4 协议族
	if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
			printf("bind fail !\r\n");
			return -1;
	}
	printf("bind ok !\r\n");
	if(-1 == listen(sfp,5))				//3.l-调用 listen 监听函数,监听用户的连接请求
	{
			printf("listen fail !\r\n");
			return -1;
	}
	printf("listen ok\r\n");
			sin_size = sizeof(struct sockaddr_in);
							//4.a-在监听到用户的请求后调用 accept 函数接受请求(R)
			nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
			if(-1 == nfp)
			{
					printf("accept fail !\r\n");
					return -1;
			}

			printf("accept ok!\r\nServer start get connect from %#x : %#x\r\n", 
									ntohl(c_add.sin_addr.s_addr), ntohs(c_add.sin_port));
			while(1)	                //567.while(1)中执行 W-R操作
			{
					memset(buffer, 0, 100);
					sprintf(buffer, "hello,welcome to my server(%d) \r\n", num++);
					send(nfp, buffer, strlen(buffer), 0);//发生函数
					usleep(500000);
			}
			close(nfp);
	close(sfp);
	return 0;
}//1.s-调用 socket 函数创建一个套接字
	if(-1 == sfp)
	{
			printf("socket fail ! \r\n");
			return -1;
	}
	printf("socket ok !\r\n");
	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;使用 IPv4 协议
	s_add.sin_addr.s_addr=htonl(INADDR_ANY);允许任何地址
	s_add.sin_port=htons(portnum);设置端口号
							//2.b-用bind 绑定函数,使用的是 IPv4 协议族
	if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
			printf("bind fail !\r\n");
			return -1;
	}
	printf("bind ok !\r\n");
	if(-1 == listen(sfp,5))				//3.l-调用 listen 监听函数,监听用户的连接请求
	{
			printf("listen fail !\r\n");
			return -1;
	}
	printf("listen ok\r\n");
			sin_size = sizeof(struct sockaddr_in);
							//4.a-在监听到用户的请求后调用 accept 函数接受请求(R)
			nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
			if(-1 == nfp)
			{
					printf("accept fail !\r\n");
					return -1;
			}

			printf("accept ok!\r\nServer start get connect from %#x : %#x\r\n", 
									ntohl(c_add.sin_addr.s_addr), ntohs(c_add.sin_port));
			while(1)	                //567.while(1)中执行 W-R操作
			{
					memset(buffer, 0, 100);
					sprintf(buffer, "hello,welcome to my server(%d) \r\n", num++);
					send(nfp, buffer, strlen(buffer), 0);//发生函数
					usleep(500000);
			}
			close(nfp);
	close(sfp);
	return 0;
}

                客户端:S C W RC

#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char **argv)
{
	int cfd;
	int recbyte;
	int sin_size;
	char buffer[1024] = {0};

	struct sockaddr_in s_add, c_add;
	unsigned short portnum = 0x8888;
	printf("Hello,welcome to client!\r\n");
	if(argc != 2)
	{
			printf("usage: echo ip\n");
			return -1;
	}
	cfd = socket(AF_INET, SOCK_STREAM, 0);	//1.s-调用 socket 函数创建一个套接字
	if(-1 == cfd)
	{
			printf("socket fail ! \r\n");
			return -1;
	}
	printf("socket ok !\r\n");

	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;					//ipv4
	s_add.sin_addr.s_addr= inet_addr(argv[1]);	//地址输入参数-要链接的IP地址
	s_add.sin_port=htons(portnum);				//端口号,1对1
	printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);
						//2.C-客户端直接链接地址(W)
	if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
			printf("connect fail !\r\n");
			return -1;
	}

	printf("connect ok !\r\n");

	while(1)
	{					//3.R-读出来自服务器的数据
			if(-1 == (recbyte = read(cfd, buffer, 1024)))
			{
					printf("read data fail !\r\n");
					return -1;
			}

			printf("read ok\r\nREC:\r\n");
			buffer[recbyte]='\0';
			printf("%s\r\n",buffer);
	}

	close(cfd);

	return 0;

}//1.s-调用 socket 函数创建一个套接字
	if(-1 == cfd)
	{
			printf("socket fail ! \r\n");
			return -1;
	}
	printf("socket ok !\r\n");

	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;					//ipv4
	s_add.sin_addr.s_addr= inet_addr(argv[1]);	//地址输入参数-要链接的IP地址
	s_add.sin_port=htons(portnum);				//端口号,1对1
	printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);
						//2.C-客户端直接链接地址(W)
	if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
			printf("connect fail !\r\n");
			return -1;
	}

	printf("connect ok !\r\n");

	while(1)
	{					//3.R-读出来自服务器的数据
			if(-1 == (recbyte = read(cfd, buffer, 1024)))
			{
					printf("read data fail !\r\n");
					return -1;
			}

			printf("read ok\r\nREC:\r\n");
			buffer[recbyte]='\0';
			printf("%s\r\n",buffer);
	}

	close(cfd);

	return 0;

}

(3)概念.什么是 TCP? 什么是 IP?
TCP/IP 是一类协议系统,它是用于网络通信的一套协议集合.TCP/IP 中文名为传输控制协议/因特网互联协议,又名网络通讯协议,是 Internet 最基本的协议、Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 TCP 协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准;
TCP/IP 协议不是 TCP 和 IP 这两个协议的合称,而是指因特网整个 TCP/IP 协议族。从协议分层模型方面来讲,TCP/IP 由四个层次组成:网络接口层、网络层、传输层、应用层。OSI 是传统的开放式系统互连参考模型,该模型将 TCP/IP 分为七层: 物理层、数据链路层(网络接口层)、网络层(网络层)、传输层(传输层)、会话层、表示层和应用层(应用层);

1) 网络接口层:
主要是指物理层次的一些接口,比如电缆等.

2) 网络层:
提供独立于硬件的逻辑寻址,实现物理地址与逻辑地址的转换

在 TCP / IP 协议族中,网络层协议包括 IP 协议(网际协议),ICMP 协议( Internet 互联网控制报文协议),以及 IGMP 协议( Internet 组管理协议).

3) 传输层:
为网络提供了流量控制,错误控制和确认服务.

在TCP / IP 协议族中有两个互不相同的传输协议: TCP(传输控制协议)和 UDP(用户数据报协议).

4) 应用层:
为网络排错,文件传输,远程控制和 Internet 操作提供具体的应用程序

(4)数据包==>套字节的形象定义
在 TCP / IP 协议中数据先由上往下将数据装包,然后由下往上拆包

装包的时候,每一层都会增加一些信息用于传输,这部分信息就叫报头,当上层的数据到达本层的时候,会将数据加上本层的报头打包在一起,继续往下传递

拆包的时候,每一层将本层需要的报头读取后,就将剩下的数据往上传.

这个过程有点像俄罗斯套娃,所以有时候人们也会用俄罗斯套娃来形容这个过程.

2.upd-网络通讯实例===============================================

 

    基于UDP的socket编程:

 

    UDP 是用户数据报协议,它是一种无连接的传输层协议,提供面向事物的简单不可靠信息传送服务,所以在一些网络质量不满意的环境下,UDP 协议数据包丢失会比较严重,会造成数据的丢失。

    UDP 的特点是他不属于连接型协议,所以资源消耗小处理速度快的优点,所以通常音频,视频和普通数据在传送时使用 UDP 较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

    

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <pthread.h>
//网口1的UDP服务器、客户端代码
void init_udp1()
{
    pthread_attr_t attr1={0};
    pthread_attr_init(&attr1);
    pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_DETACHED);
    if(pthread_create(&udp1_thread_id,NULL,udp1_server_process,0) !=0 )
    {
        printf("UserTimer thread (create) error\n");
        //while(1);
    }
    printf("\n=======udp1 server thread ok======\n");
    pthread_attr_t attr1_c={0};
    pthread_attr_init(&attr1_c);
    pthread_attr_setdetachstate(&attr1_c,PTHREAD_CREATE_DETACHED);
    if(pthread_create(&udp1_c_thread_id,NULL,udp1_client_process,0) !=0 )
    {
        printf("UserTimer thread (create) error\n");
        //while(1);
    }
    printf("\n=======udp1 client thread ok======\n");
}
//网口2的UDP服务器、客户端代码
void init_udp2()
{
    pthread_attr_t attr2={0};
    pthread_attr_init(&attr2);
    pthread_attr_setdetachstate(&attr2,PTHREAD_CREATE_DETACHED);
    if(pthread_create(&udp2_thread_id,NULL,udp2_server_process,0) !=0 )
    {
        printf("UserTimer thread (create) error\n");
    }
    

    pthread_attr_t attr2_c={0};
    pthread_attr_init(&attr2_c);
    pthread_attr_setdetachstate(&attr2_c,PTHREAD_CREATE_DETACHED);
    if(pthread_create(&udp2_c_thread_id,NULL,udp2_client_process,0) !=0 )
    {
        printf("UserTimer thread (create) error\n");
    }
    
}
int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        printf("Usage:./select_server [ip] [port]\n");
        //return 1;
    }

    init_udp1();
    init_udp2();
    while(1)
    {
        ;
    }
	printf("\n=======exit======\n");
       return 0;
}

(1)网口2 服务器 代码

//该服务器仍是属于回显服务器,接收到什么就回复什么
void *udp2_server_process(void *arg)
{
	struct sockaddr_in server;
    struct sockaddr_in client;
    char buf[BUFFER_SIZE];
    int32_t len = sizeof(client);
    int32_t ret = 0;
    int32_t file_len = 0;
    printf("\n=======udp2 server thread ok======\n");
    int32_t sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("create socket failed!");
        exit(1);
    }
    bzero(&server, sizeof(struct sockaddr_in));
    server.sin_family = AF_INET;
    server.sin_port = htons(udp2_port);     /*本机IP-端口 主机字节序转化成网络字节序 */
    server.sin_addr.s_addr = inet_addr(udp2_ip); /*本机IP 字符串转换in_addr的函数 */
    /* 绑定服务器 */
    if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)    
    {
        perror("bind failed!");
        exit(1);
    }
    while(1)
    {
        ret = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&client, &len);
        if (ret < 0)
        {
            perror("recvfrom failed!");
            exit(1);
        }
        buf[ret] = '\0';
        printf("client message: %s\n", buf);
        printf("client's ip is %s, port is %d.\n", inet_ntoa(client.sin_addr), htons(client.sin_port));
    
        /**< 向客户端发送信息 */
        if (sendto(sockfd, "Welcome to server", BUFFER_SIZE, 0, (struct sockaddr *)&client, len) < 0)
        {
            perror("send file len to client error");
        }
    }
}

 

(2)网口2的客户端代码

 

void *udp2_client_process(void *arg)
{
   struct sockaddr_in server;
    struct sockaddr_in peer;
    char buf[BUFFER_SIZE];
    int32_t len = sizeof(peer);
    char sendbuf[BUFFER_SIZE] = "welcome to client";
    int32_t num = 0;
    printf("\n=======udp2 client thread ok======\n");
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("create udp2 socket failed!");
        exit(1);
    }
    bzero(&server, sizeof(struct sockaddr_in));
    server.sin_family = AF_INET;
    server.sin_port = htons(udp2_r_port);                //远端服务器的端口
    server.sin_addr.s_addr = inet_addr(udp2_r_ip);//远端服务器的地址
    while(1)
    {
        if (sendto(sockfd, sendbuf, BUFFER_SIZE, 0, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            perror("sendto socket failed!");
            exit(1);
        }

        if ((num = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&peer, &len)) < 0)
        {
            perror("recvfrom socket failed!");
            exit(1);
        }
        
        buf[num] = '\0';
        printf("Server Message: %s\n", buf);
    }
    

    close(sockfd);

    return 0;
}

Makefile

.SUFFIXES : .x .o .c .s

CC := arm-linux-gcc
STRIP := arm-linux-strip

TARGET = udp_app
SRCS := main.c udp.c
LIBS = -lpthread -lc -lgcc

all:
	$(CC) -static $(SRCS) -o $(TARGET) $(LIBS)
	$(STRIP) $(TARGET)
	cp -va $(TARGET) /nfsroot/
clean:
	rm -f *.o
	rm -f *.x
	rm -f *.flat
	rm -f *.map
	rm -f temp
	rm -f *.img
	rm -f $(TARGET)
	rm -f *.gdb

测试结果

        怎么看UDP比tcp更简单,不过TCP也一定不难!!!

 

注意:因为服务器需要在ubuntu上运行,故采用电脑的编译器编译:编译指令gcc -o server server.c

而客户端再开发板(arm内核)上运行,故采用arm的编译器:编译指令 arm-none-linux-gnueabi-gcc -o client client.c 编译 client.c

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux基础操作之8.套接字网络通讯tcp/udp 的相关文章

  • 嵌入式 3-笔试-linux/c/c++(重复的题目就是高频考查题) 8个大厂精选收集50题

    Linux开发相关的大厂面试题 xff0c 主要是Linux服务器开发相关 xff0c 此处仅作优秀试题摘录 xff0c 详细文档 xff0c 可自行到文档csdn下载区下载 xff0c 同时 xff0c 如涉及侵权内容 请及时告知 xff
  • 关于Runnable 和 Thread的应用场景

    摘自StackOverflow 个人觉得比较靠谱的答案 xff0c 细节请看url http stackoverflow com questions 541487 implements runnable vs extends thread
  • RT-Thread嵌入式操作系统 开发笔记(上)

    更详细的参考链接 0 准备 xff1a 环境准备 xff1a MDK ARM 5 30 正式版或评估版 xff0c 5 14 版本及以上版本均可 43 破解软件 STM32F103 pack 库文件 百度云盘云盘文件 1 文件 xff0c
  • RT-Thread嵌入式操作系统 开发笔记(中)

    9 生产者消费者问题模型 xff08 验证代码producer consumer c xff09 生产者消费者问题是 一个经典的 多线程同步问题 有两个线程 一个生产者线程和一个消费者线程 两个线程共享二个初始为空 固定大小为n的缓存区 生
  • 嵌入式软件基础问题-转

    volatile关键字的作用 直译为 易变 xff0c 与const相反 用volatile定义的变量 xff0c 在每一次被访问时都是从内存中读取该量的值 xff0c volatile不允许编译器优化该值到寄存器 xff0c 所以取值时不
  • 嵌入式操作系统RT-Thread和Freertos资源对比总结 转

    Freertos是一个国外推出的一个迷你的实时操作系统内核 xff0c 开源 xff0c 功能包括 xff1a 任务管理 时间管理 信号量 消息队列 内存管理 记录功能 软件定时器 协程等 xff0c 可基本满足较小系统的需要 RT Thr
  • 虚拟机更改IP 连接失败 问题解决Destination Host Unreachable

    问题1 xff1a 虚拟机原来是ens33的ip 1 100 xff0c 可以联网 xff0c 改为3 66就无法联网 xff0c 再改回1 100 xff0c 依然无法联网 如图 解决方法 xff1a 重启网卡管理器即可 xff1a se
  • NUC980 jtag0 默认管脚复用问题

    NUC980DK61YC 使用G13 xff08 管脚编号是205 xff09 用作普通io口 xff0c 出现报错 报错 xff1a echo 205 gt sys class gpio export Please Check GPIOG
  • usb的device模式hid配置错误点

    将usb做从机 xff0c hid通信操作 xff08 模拟串口 xff0c 模拟u盘 xff0c hid通信 xff09 内核设定 1 模拟u盘 2 模拟串口 3 hid通信 1 报错 xff1a insmod libcomposite
  • nuc980 串口问题 串口断帧 丢帧问题

    NUC980 的性能不错 xff0c 串口速率号称达到3Mbps xff08 代码级有4M的极限 xff09 xff0c 并且带有流控性能 xff1b 经过单独测试3Mbps下有千分之三的丢包率 xff08 NUC980和电脑的串口助手交互
  • 2021-09-14 uboot移植开发

    引言 xff1a 最近要改动uboot xff0c 实现像微软PC上 xff0c u盘一键刷机或手机上安全模式下刷机的操作 专门去好好研究了点uboot的启动过程 xff1b 以下为总结 xff1a 嵌入式系统 微软 PC bootload
  • JAVA 泛型中的<T> 和 <?> 的应用场景

    在JAVA 泛型中 xff0c 经常看到 lt gt 应用场景为当不确定类型时 因为泛型的输入参数是类型 xff0c 而有一些状况下我们并不能确定类型
  • 当ctrl + c无法打断linux应用程序的执行时(CPU占比过大),该注意什么 ?

    如题 xff0c 问题显示如下 xff1b 经过测试 xff1a 发现是线程资源无法及时是否导致的 xff1b 每个线程都是while xff08 1 xff09 如果线程之间没有设置优先级的话 xff1b 当一个线程的while xff0
  • uboot内读写gpio操作实现

    目的 xff1a 为uboot添加判断gpio电平的操作 xff0c 修改对内核的跳转 1 查参考手册Register Map R read only W write only R W both read and write 在uboot跳
  • 文件传输校验-crc32校验算法

    文件传输校验 xff0c 用于升级的时候使用较多 xff1b 场景 xff1a 传输前先获取文件长度 xff0c 获取文件内容 xff0c 然后对文件校验 获得u32的校验信息变量 xff1b 设定每包长度 xff0c 将其封装到握手包 x
  • 打包QT的exe程序,解决Qt5Guid.dll,QtNetwork.dll等找不到的问题

    解决问题 xff1a 在用qt写完一个项目之后 xff0c 要生成一个exe文件 xff0c 让他人使用 打包程序 xff0c 工具 xff1a windows下的qt5 12 1 发布 xff1a 发布这个选项的 xff0c 也就是左下角
  • 解决段错误,系统应用core dump的分析

    解决段错误 xff0c 系统应用core dump的分析 这个错误在单片机上往往以hardfault的错误出现 xff0c 分析思路都是分析堆栈的位置 xff1b 单片机的编译软件 xff0c 如果可以仿真 xff08 比如keil或者IA
  • 作为无人机方面做嵌入式编写的飞控总结0

    导 xff1a 作为在专业公司的一名研制飞控 xff08 飞行控制器 xff09 的工程师 xff0c 飞控代码的编写会涉及方方面面 xff1b 如果团队是几十人或者个位的人数 xff0c 分配下来 xff1a 飞手 xff0c 销售 xf
  • 大疆osdk开发遇到的bug的解决 小结

    osdk 即dji大疆onboard sdk 用来做二次开发的的开发包 我使用的ONBOARD SDK 版本是 3 6 0 用于A3和N3的二次开发 官方的开发文档链接 xff1a https developer dji com onboa
  • 作为无人机方面做嵌入式编写的飞控总结1-基本协议驱动介绍1

    基本的驱动 要算标准的串口 iic和spi协议不可缺席 xff1b 1 作为单片机初学者必备知识点和重要知识点 xff0c 在linux系统编成之中依然还发挥很大作用 xff0c 因为这三个协议使用的是在太多了 xff1b 首先废话不多说

随机推荐