网络通信(基于TCP/IP实现客户端/服务器的通信)

news/2024/9/23 8:36:10/

编程结构

被连接者需要完成的任务(服务端):
1、创建socket内核对象,内核创建完成后会返回它的描述符(该描述只是为了完成连接,三次握手)
2、准备本机地址(ip地址+端口号)
3、绑定(把本机地址与socket对象进行绑定)
4、开启监听,并设置排队的队列长度
5、等待连接,连接成功后,内核会再返回一个连接成功的Socket描述符,专门用来通信
for(;;)
{
    6、接收请求
    7、返回结果
}
8、关闭通信的Socket对象
9、关闭连接的Socket对象

连接者需要完成的任务(客户端):
1、创建socket内核对象,内核创建完成后会返回它的描述符
2、准备被连接者的地址(ip地址+端口号)
3、发起连接,使用Socket+地址(ip地址+端口号)发起连接请求
for(;;)
{
    4、发送请求
    5、接收结果
}
6、关闭Socket对象

相关函数

int socket(int domain, int type, int protocol);
功能:创建Socket对象
domain:
    AF_UNIX, AF_LOCAL   采用本地socket文件进行通信,如果用它则只能本机上的两个进程进行通信
    AF_INET             IPv4地址
    AF_INET6               IPv6地址
type:
    SOCK_STREAM    数据流    TCP
    SOCK_DGRAM 报文 UDP
protocol:
    特殊通信协议,写0即可
返回值:
    成功则返回Socket对象描述符,失败返回-1。

// 基本地址类型,它是socket系列接口的表面参数,而实际使用的是sockaddr_un或sockaddr_in,我们需要把sockaddr_in强制转换成sockaddr类型。
struct sockaddr_in 
{
    sa_family_t sin_family;        // 地址类型,与domain保持一致即可
    in_port_t sin_port;            // 端口号,网络字节序的2字节整数
    struct in_addr sin_addr.s_addr;    // IP地址,网络字节序的4字节整数
};

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定Socket对象与通信地址
sockfd:Socket对象描述符
addr:通信地址,实际提供可能是sockaddr_un或sockaddr_in,需要对它们进行强制转换
addrlen:addr结构体的字节数
返回值:成功返回0,失败返回-1
    
int listen(int sockfd, int backlog);
功能:开启Socket对象的监听
sockfd:Socket地址描述符
backlog:备胎的数量
    
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:等待连接,没有成功连接之前,会进入阻塞状态
sockfd:Socket对象描述符
addr:用于存储连接者的通信地址
addrlen:
    既是输入(告诉accetp接口,addr结构体的字节数),也是输出(实际接收到的addr结构的字节数)
返回值:建立连接的,能够通信的Socket对象描述符,失败返回-1
    
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:让sockfd对象向addr地址发起连接
sockfd:Socket对象描述符
addr:连接目标的地址
addrlen:addr结构体的字节数
返回值:成功返回0,失败返回-1
    
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:从Socket对象读接收干字节
sockfd:Socket对象描述符
buf:接收数据的内存块首地址
len:buf的字节数
flags:是否阻塞,写0即可
返回值:成功接收到了多少个字节,失败返回-1
    
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:通过Socket对象发送若干字节
sockfd:Socket对象描述符
buf:要发送的内存块首地址
len:要发送的字节数
flags:是否阻塞,写0即可
返回值:成功发送了多少个字节,失败返回-1
    
int close(int fd);
功能:关闭fd描述所代表的内核对象
    
uint16_t htons(uint16_t hostshort);
功能:把本地字节序的 unsigned short 类型的数据转换网络字节序
    
in_addr_t inet_addr(const char *cp);
功能:把字符串格式 点分十进制的ip地址 转换成网络字节序的4字节ip地址

代码:

服务端:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main(int argc,const char* argv[])
{// 创建socket对象int server_fd = socket(AF_INET,SOCK_STREAM,0);if(0 > server_fd){perror("socket");return -1;}// 准备本机地址struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(2233);addr.sin_addr.s_addr = inet_addr("10.0.2.15");socklen_t addrlen = sizeof(addr);// 绑定socket对象和地址	if(bind(server_fd,(struct sockaddr*)&addr,addrlen)){perror("bind");return -2;}// 开启监听if(listen(server_fd,6)){perror("listen");return -3;}// 等待连接int sockfd = accept(server_fd,(struct sockaddr*)&addr,&addrlen);if(0 > sockfd){perror("accept");return -4;}char buf[BUFSIZ];for(;;){// 接收数据int ret = read(sockfd,buf,BUFSIZ);if(0 >= ret || !strcmp("quit",buf))break;printf("recv:%s byte:%d\n",buf,ret);strcat(buf,",return!");// 返回数据ret = write(sockfd,buf,strlen(buf)+1);if(0 >= ret)break;}printf("通信结束!\n");// 关闭负责通信的socket对象close(sockfd);// 关闭负责连接的socket对象close(server_fd);return 0;
}
客户端:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main(int argc,const char* argv[])
{// 创建socket对象int sockfd = socket(AF_INET,SOCK_STREAM,0);if(0 > sockfd){perror("socket");return -1;}// 准备服务端的地址struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(2233);addr.sin_addr.s_addr = inet_addr("10.0.2.15");socklen_t addrlen = sizeof(addr);// 连接if(connect(sockfd,(struct sockaddr*)&addr,addrlen)){perror("connect");return -2;}char buf[BUFSIZ];for(;;){printf(">>>");scanf("%s",buf);// 发送数据int ret = write(sockfd,buf,strlen(buf)+1);if(0 >= ret || !strcmp("quit",buf))break;// 接收数据ret = read(sockfd,buf,BUFSIZ);if(0 >= ret)break;printf("recv:%s byte:%d\n",buf,ret);}	printf("通信结束!\n");// 关闭socket对象close(sockfd);return 0;
}


http://www.ppmy.cn/news/1508840.html

相关文章

RCE之无参数读取文件

什么是无参数&#xff1f; 顾名思义&#xff0c;就是只使用函数&#xff0c;且函数不能带有参数&#xff0c;这里有种种限制&#xff1a;比如我们选择的函数必须能接受其括号内函数的返回值&#xff1b;使用的函数规定必须参数为空或者为一个参数等 例题&#xff1a; <?…

麻雀搜索算法(SSA)与支持向量机(SVM)结合的预测模型(SSA-SVM)及其Python和MATLAB实现

### 引言 随着科技的快速发展&#xff0c;锂离子电池被广泛应用于电动汽车、便携式电子设备以及可再生能源存储等领域。有效预测锂离子电池的剩余寿命&#xff08;Remaining Useful Life, RUL&#xff09;对于提升电池的使用安全性和经济性具有重要意义。传统的RUL预测方法往往…

Covalent(CXT)与Sei合作,为扩展以太坊应用提供数据解决方案

Covalent Network&#xff08;CXT&#xff09;是领先的模块化数据基础设施层&#xff0c;致力于解决长期数据可用性&#xff0c;并为 AI 提供可验证的结构化数据。目前 Covalent Network&#xff08;CXT&#xff09;已经与首个并行化 EVM 区块链——Sei 达成了新的合作&#xf…

TCFormer:通过标记聚类Transformer实现视觉识别

摘要 Transformer在计算机视觉领域得到了广泛应用&#xff0c;并取得了显著成功。大多数最先进的方法将图像分割成规则网格&#xff0c;并用视觉标记表示每个网格区域。然而&#xff0c;固定的标记分布忽略了不同图像区域的语义含义&#xff0c;导致性能次优。为了解决这个问题…

王立铭脑科学50讲——02篇,心智活动是如何发生的

王立铭脑科学50讲——02篇&#xff0c;心智活动是如何发生的 我对课程中感兴趣的点 1、脑的结构可以细分到一个个神经细胞&#xff0c;但脑的功能神经细胞彼此连接实现的。 我由此想到&#xff0c;人工神经网络&#xff0c;也是利用激活函数、权重值、偏置量来模拟人工神经网…

PHP项目任务系统小程序源码

&#x1f680;解锁高效新境界&#xff01;我的项目任务系统大揭秘&#x1f50d; &#x1f31f; 段落一&#xff1a;引言 - 为什么需要项目任务系统&#xff1f; Hey小伙伴们&#xff01;你是否曾为了杂乱的待办事项焦头烂额&#xff1f;&#x1f92f; 或是项目截止日逼近&…

Oracle: oracle大小写敏感问题

oracle大小写敏感含义&#xff1a;比如创建表A和a&#xff0c;A和a是两个不同的表&#xff08;表名不同&#xff09;。 oracle大小写不敏感含义&#xff1a;比如创建了A表就不能创建a表&#xff0c;将A和a看成是相同的表&#xff08;表名相同&#xff09;。 1、查询用户是否存…

媒体资讯视频数据采集-lux的使用

lux(annie)是个github上的一个开源项目&#xff0c;可以使用他来下载网上各个平台的视频、音频、图片。 支持的站点也不少**&#xff08;ps: 对于一些反爬机制较好的网站可能不能下载&#xff0c;比如抖音、快手&#xff09;** ​ github使用说明页面提供windows、linux、M…