当前位置: 首页 > news >正文

服务端与多客户端照片的传输,recv,send

一、照片传输

server.c

/*===============================================
*   文件名称:server.c
*   创 建 者:
*   创建日期:2025年02月07日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
int main(int argc, char *argv[])
{ signal(SIGPIPE,SIG_IGN);//创建套接字int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socket");exit(-1);}printf("socket success!\n");//绑定本机ip地址和端口号struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(6666);saddr.sin_addr.s_addr = inet_addr("192.168.6.44");int s_len = sizeof(saddr);int ret = bind(sockfd,(struct sockaddr *)&saddr,s_len);if(ret < 0){perror("bind");exit(-1);}printf("bind success\n");//设置监听套接字ret = listen(sockfd,10);if(ret < 0){perror("listen");exit(-1);}printf("listen success\n");//等待客户端连接printf("wait for a new client\n");struct sockaddr_in caddr;memset(&caddr,0,sizeof(caddr));int c_len = sizeof(caddr);while(1){int connfd = accept(sockfd,(struct sockaddr *)&caddr,&c_len);if(connfd < 0){perror("accept");exit(-1);}printf("link success\n");printf("client_ip = %s  client_port = %d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));int fd = open("1.jpg",O_RDONLY);if(-1 == fd){perror("open");close(connfd);continue;}char data[1024],len[5];int ret;//每次读取文件的实际长度while(1){//读取文件内容ret = read(fd,data,1024);//将长度变成字符串sprintf(len,"%d",ret);//向客户端发送这一次的长度if(-1 == write(connfd,len,5))break;if(0 == ret)break;//向客户端发送这一次的正文if(-1 == write(connfd,data,ret))break;}close(fd);close(connfd);}return 0;
} 

client.c

/*===============================================
*   文件名称:client.c
*   创 建 者:
*   创建日期:2025年02月07日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>int main(int argc, char *argv[])
{if(argc < 3){printf("Usage:%s <IP><port>\n",argv[0]);exit(-1);}//创建套接字int sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socket");exit(-1);}printf("socket success!\n");//发起连接struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[2]));saddr.sin_addr.s_addr = inet_addr(argv[1]);int s_len = sizeof(saddr);int ret = connect(sockfd,(struct sockaddr *)&saddr,s_len);if(ret < 0){perror("connect");exit(-1);}int fd = open("1.jpg",O_WRONLY|O_CREAT,0777);if(-1 == fd){perror("open");exit(-1);}char data[1024],len[5];int size;while(1){//固定读取5字节代表这次传输文件正文长度ret = read(sockfd,len,5);if(0 >= ret)break;size = atoi(len);if(0 == size){puts("over");break;}//读取正文ret = read(sockfd,data,size);if(0 >= ret)break;write(fd,data,size);}//关闭套接字close(fd);close(sockfd);return 0;
} 

二、循环服务器模型

服务器一次只能处理一个连接请求,只有将对应客户端的请求处理完成然后与之断开连接再与下一个客户端建立连接。

	listenfd = socket(...);bind(...);listen(...);while(1){int confd = accept(...);while(1){//处理对应的客户端请求.}}

三、TCP粘包

TCP粘包:tcp的数据包边界不明显。

解决方案:

  1. ​ 遍历每个字节寻找消息的格式头解析;

  2. ​ 保证完整接收期望的数据

    1char buf[1024];
    int count, size, ret; //count:实际读取字节数 size:期望读取字节数
    ...count = 0;while(count < size){ret = read(confd, buf+count, size-count);count += ret;}2:在服务器每次发送完整数据后睡眠一段时间3while(size > recv(confd, buf, size, MSG_PEEK));recv(confd, buf, size, 0);4:recv(confd, buf, size, MSG_WAITALL);  //不稳定,会被信号影响
    

四、recv/send函数详解

recv/send函数专门用来进行网络通信的函数

recv:接收

#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
返回值:出错-1  对端关闭连接0 >0表示实际读取的字节数
int sockfd: 通信套接字
void *buf: 接收数据存放的缓冲区
size_t len: 期望接收的字节数
int flags: 0与read一样MSG_OOB:带外数据(紧急数据:只有1个字节有效并且一个套接字至多只有一个紧急数据)MSG_PEEK: 查询缓冲区数据但是不会取走对应数据MSG_DONTWAIT:非阻塞模式MSG_WAITALL:保证读到期望字节数的数据

send:发送

#include <sys/types.h>
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
返回值:出错-1  >0表示实际发送的字节数
int sockfd: 通信套接字
void *buf: 发送数据存放的缓冲区首地址
size_t len: 发送字节数
int flags: 0与write一样MSG_OOB:带外数据(紧急数据:只有1个字节有效并且一个套接字至多只有一个紧急数据)MSG_NOSIGNAL:当对端连接断开时发送数据不产生SIGPIPE信号

五、并发服务器模型

服务器可以同时处理多个客户端的请求,就是并发服务器。

1、多线程实现并发服务器模型

将每个客户端的请求都创建对应线程去处理

void *client_handler(void *arg);int main()
{listenfd = socket(...);bind(...);listen(...);while(1){int confd = accept(...);pthread_create(.., .., client_handler, (void *)confd);...;}
}
http://www.lryc.cn/news/533784.html

相关文章:

  • JS实现灯光闪烁效果
  • SpringCloud面试题----Nacos和Eureka的区别
  • verilog练习:i2c slave 模块设计
  • 3.5 Go(特殊函数)
  • Android的MQTT客户端实现
  • 国产编辑器EverEdit - 编辑辅助功能介绍
  • WPF 在后台使TextBox失去焦点的方法
  • 工作案例 - python绘制excell表中RSRP列的CDF图
  • CTF SQL注入学习笔记
  • element-plus el-tree-select 修改 value 字段
  • 基于javaweb的SpringBoot小区智慧园区管理系统(源码+文档+部署讲解)
  • SpringBoot学习之shardingsphere实现分库分表(基于Mybatis-Plus)(四十九)
  • 23.PPT:校摄影社团-摄影比赛作品【5】
  • Baumer工业相机堡盟相机的相机传感器芯片清洁指南
  • Spring Boot 整合 JPA 实现数据持久化
  • 快速在wsl上部署学习使用c++轻量化服务器-学习笔记
  • 【R语言】数据操作
  • MariaDB MaxScale实现mysql8主从同步读写分离
  • 【python】简单的flask做页面。一组字母组成的所有单词。这里的输入是一组字母,而输出是所有可能得字母组成的单词列表
  • 单片机之基本元器件的工作原理
  • 吴恩达深度学习——卷积神经网络的特殊应用
  • 安宝特方案 | AR助力制造业安全巡检智能化革命!
  • Unity-Mirror网络框架-从入门到精通之Discovery示例
  • 项目的虚拟环境的搭建与pytorch依赖的下载
  • 现代前端工程化实践:高效构建的秘密
  • ARM Linux Qt使用JSON-RPC实现前后台分离
  • 【C++篇】C++11新特性总结1
  • 【Nginx + Keepalived 实现高可用的负载均衡架构】
  • 使用外骨骼灵活远程控制协作机器人案例
  • Centos Stream 10 根目录下的文件夹结构