tcp/ip实现点对点通信(socket编程)

2024-03-11 17:32

本文主要是介绍tcp/ip实现点对点通信(socket编程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们日常的网络其实是由很多层来组成的,有硬件,有代码和一些约定好的通信协议组成还有我们使用的微信聊天,qq聊天等;其中分层主要有:OSI七层网络模型及TCP/IP的四层参考模型:

在这里插入图片描述

各层的主要作用及常用协议有:

(1)物理层:数据转换(把数字信号转为电信号)(arp,rarp)
(2)数据链路层:保证数据的正确传输(校验)
(3)网络层:寻找路由与确认主机(ip,icmp,igmp)
(4)传输层:按照规定协议来收发数据(tcp/ip,udp)
(5)会话层,表示层,应用层:这三层是自己通过socket编程,来设置客户端与主机间怎样去通信的网络编程的重点!!!


下面是关于Linux下socket编程的一些函数:

创建监听套接字函数:

//头文件
#include <sys/types.h>          
#include <sys/socket.h>//函数原型
int socket(int domain, int type, int protocol);//函数介绍
/****************************************************
函数作用:创建一个套接字,用于通信(socket翻译为插座,意为在通信协议与进程间通过一个API后便能进行通信)函数形参:domain:域(选择的通信协议)AF_INET/PF_INET:   网际协议,IPv4AF_INET6/PF_INET6: 网际协议,IPv6AF_UNIX/PF_UNIX: 本地协议,可写成AF_LOCAL/PF_LOCALtype:类型SOCK_STREAM:流式套接字,对应TCPSOCK_DGRAM:数据报套接字,对应UDPprotocol:协议(一般为0),因为主要的通信协议为tcp/ip或udp函数返回值:成功: 创建成功的套接字文件描述句柄失败: -1
***************************************************/


绑定套接字函数:

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//函数介绍
/****************************************************
函数作用:初始化默认端口及绑定套接字和地址函数形参:sockfd:使用socket函数申请成功的套接字文件句柄addr:初始化的端口及使用的协议和IP地址等(一般不使用struct sockaddr这个结构体,会使用struct sockaddr_in这个结构体)addrlen:addr的长度函数返回值:成功: 创建成功的套接字文件描述句柄失败: -1
***************************************************/
绑定端口及IP一般只在服务器上绑定,因为服务器是需要给很多个客户端来连接的,因此客户端可以不绑定,然后系统会给客户端分配一个空闲的端口等,可以在一定程度上减轻系统压力

由于struct sockaddr这个结构体是用于存放端口及IP等信息的结构体,但由于我们给它初始化时IP和端口及使用的协议都在sa_family里面,过于麻烦于是大牛们想了一个办法:用一个内存大小和这个结构体一样的来替换它,就是struct sockaddr_in这个结构体

struct sockaddr {sa_family_t sa_family;char        sa_data[14];}//===================用于替换的结构体=========================
特殊地址结构体 —— IPv4地址结构体:
struct sockaddr_in
{u_short sin_family; // 地址族u_short sin_port; // 端口struct in_addr sin_addr; // IPV4地址char sin_zero[8];
};struct in_addr
{
in_addr_t s_addr; // 无符号32位网络地址
};特殊地址结构体 —— IPv6地址结构体:
struct sockaddr_in6
{u_short sin6_family;    // 地址族__be16 sin6_port;      // 端口__be32 sin6_flowinfo; // 流信息
struct in6_addr sin6_addr; // IPv6地址__u32 sin6_scope_id;
};特殊地址结构体 ——UNIX域地址结构体:
struct sockaddr_un
{           u_short sun_family; // 地址族char sun_path[108]; // 套接字文件路径
};


监听连接请求函数:

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
int listen(int sockfd, int backlog);//函数介绍
/****************************************************
函数作用:把sockfd套接字句柄由主动状态转为被动连接状态函数形参:sockfd:使用socket函数申请成功的套接字文件句柄backlog: 当正在处理accept时候有客户端链接, 就入队列,表示队列长度(一般设置为5即可)函数返回值:成功: 0失败: -1
***************************************************/


接受连接函数:

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//函数介绍
/****************************************************
函数作用:接收其他客户端的连接请求,如果没有连接将会阻塞等待函数形参:sockfd:使用socket函数申请成功的套接字文件句柄addr: 用于保存当前连接的客户端的IP,端口等信息addrlen:addr这个结构体的大小(必须是一个变量的地址,不能使用sizeof(addr)!!!)函数返回值:成功: 返回当前连接的客户端的本地句柄失败: -1
***************************************************/


连接服务器函数:

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//函数介绍
/****************************************************
函数作用:接收其他客户端的连接请求,如果没有连接将会阻塞等待函数形参:sockfd:使用socket函数申请成功的套接字文件句柄addr: 包含被连接端的IP地址+端口号等addrlen:addr这个结构体的大小(必须是一个变量的地址,不能使用sizeof(addr)!!!)函数返回值:成功: 返回当前连接的客户端的本地句柄失败: -1
***************************************************/


发送数据函数:

常见的发送数据函数有: send() , write()、 sendto()–>常用于udp通信,这里只讲send,一般为客户端给服务器发送数据

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);//函数介绍
/****************************************************
函数作用:用于发送数据函数形参:sockfd:已连接套接字buf:即将被发送的数据len:数据长度flags:发送标志。MSG_NOSIGNAL:当对端已关闭时,不产生SIGPIPE信号MSG_OOB:发送紧急(带外)数据,只针对TCP连接函数返回值:成功: 返回成功发送的字节数失败: -1
***************************************************/


接收数据函数:

常见的发送数据函数有: recv(), read(), recvfrom()–》可接收发送方的IP+端口,这里只讲recvfrom,一般为客户端给服务器发送数据

//头文件
#include <sys/types.h>        
#include <sys/socket.h>//函数原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);//函数介绍
/****************************************************
函数作用:用于发送数据函数形参:sockfd:已连接套接字buf:即将被发送的数据len:数据长度flags:发送标志。MSG_NOSIGNAL:当对端已关闭时,不产生SIGPIPE信号MSG_OOB:发送紧急(带外)数据,只针对TCP连接函数返回值:成功: 返回成功发送的字节数失败: -1
***************************************************/

下面直接上代码

服务器端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>void *client_recv(void* arg);
int main(int argc, char **argv)
{if(argc < 2){printf("Run: server port\n");exit(1);}//1.创建套接字int sockfd = socket(AF_INET,SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");exit(1);}//2.绑定-地址, 端口struct sockaddr_in my_addr;memset(&my_addr, 0, sizeof(my_addr));my_addr.sin_family=AF_INET;my_addr.sin_port=htons( atoi(argv[1]) );//网络字节序my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//网络字节序--在任意ip上绑定int ret  = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));if(ret < 0){perror("bind error");exit(1);}//3.监听--启动服务器ret = listen(sockfd, 5);if(ret < 0){perror("listen error");exit(1);}//4.接受连接//定义保存客户端地址的结构体struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);//4.接受链接--没有客户端链接是处于阻塞状态int  clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);if(clientfd < 0){perror("accept error");}//创建线程--用于接收客户端数据pthread_t id = 0;ret = pthread_create(&id, NULL, client_recv, (void*)&clientfd);//把与客户端通信用的套接字传递给线程if(ret <0){perror("create error");exit(1);}char buffer[128]={0};while(1){//给客户端发送数据scanf("%s", buffer);send(clientfd, buffer, strlen(buffer), 0);//清空buffermemset(buffer, 0, sizeof(buffer));}
}void *client_recv(void* arg)
{//获取客户端套接字int clientfd = *((int*)arg);char buffer[128]={0};while(1){//接收数据recv(clientfd, buffer, sizeof(buffer), 0);//输出printf("%s\n", buffer);//清空buffermemset(buffer, 0, sizeof(buffer));}}
客户端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
void *server_recv(void* arg);int main(int argc, char **argv)
{if(argc < 3){printf("Run: server ip port\n");exit(1);}//1.创建套接字int sockfd = socket(AF_INET,SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");exit(1);}//2. 链接服务器struct sockaddr_in seraddr;memset(&seraddr,0, sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons( atoi(argv[2]) );seraddr.sin_addr.s_addr = inet_addr( argv[1] );//服务器地址转网络字节序32位int ret = connect(sockfd, (struct sockaddr*)&seraddr, sizeof(seraddr));if(ret < 0){perror("connect error");exit(1);}//创建线程//创建线程--用于接收服务端数据pthread_t id = 0;ret = pthread_create(&id, NULL, server_recv, (void*)&sockfd);//把与客户端通信用的套接字传递给线程if(ret <0){perror("create error");exit(1);}//主线程发送数据char buffer[128]={0};while(1){//给客户端发送数据scanf("%s", buffer);send(sockfd, buffer, strlen(buffer), 0);//清空buffermemset(buffer, 0, sizeof(buffer));}
}void *server_recv(void* arg)
{//获取客户端套接字int sockfd = *((int*)arg);char buffer[128]={0};while(1){//接收数据recv(sockfd, buffer, sizeof(buffer), 0);//输出printf("%s\n", buffer);//清空buffermemset(buffer, 0, sizeof(buffer));}}

这篇关于tcp/ip实现点对点通信(socket编程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/798531

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识