Linux网络编程-极简HTTPUDP服务器
HTTP服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8080
#define BUFFER_SIZE 2048void handle_client(int client_socket) {char buffer[BUFFER_SIZE];recv(client_socket, buffer, sizeof(buffer) - 1, 0); printf("Received request:\n%s\n", buffer);char response[] = "HTTP/1.1 200 OK\r\n""Content-Type: text/plain\r\n""Content-Length: 15\r\n""Connection: close\r\n\r\n""Hello, World!\r\n";send(client_socket, response, sizeof(response) - 1, 0); close(client_socket);
}int main() {int server_socket, client_socket;struct sockaddr_in server_address, client_address;socklen_t client_len;server_socket = socket(AF_INET, SOCK_STREAM, 0);if (server_socket == -1) {perror("Could not create socket");exit(1);}server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = INADDR_ANY;server_address.sin_port = htons(PORT);if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {perror("Bind failed");exit(1);}if (listen(server_socket, 10) == -1) {perror("Listen failed");exit(1);}printf("HTTP server is running on port %d ...\n", PORT);while (1) {client_len = sizeof(client_address);client_socket = accept(server_socket, (struct sockaddr *)&client_address, &client_len);if (client_socket == -1) {perror("Accept failed");continue;}handle_client(client_socket);}close(server_socket);return 0;
}
HTTP客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>#define SERVER_PORT 8080
#define BUFFER_SIZE 2048int main(int argc, char *argv[]) {int client_socket;struct sockaddr_in server_address;char buffer[BUFFER_SIZE];// 检查命令行参数if (argc != 2) {printf("Usage: %s <Server IP>\n", argv[0]);exit(1);}client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket == -1) {perror("Could not create socket");exit(1);}server_address.sin_family = AF_INET;server_address.sin_port = htons(SERVER_PORT);if (inet_pton(AF_INET, argv[1], &server_address.sin_addr) <= 0) {perror("inet_pton() failed");exit(1);}// 连接到服务器if (connect(client_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {perror("Connect failed");close(client_socket);exit(1);}// 向服务器发送HTTP请求char request[] = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";send(client_socket, request, strlen(request), 0);// 接收服务器响应int bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0);if (bytes_received == -1) {perror("Error receiving data");close(client_socket);exit(1);}buffer[bytes_received] = '\0';printf("Received from server:\n%s\n", buffer);close(client_socket);return 0;
}
或者在浏览器或者使用curl工具访问http://localhost:8080,也能够看到来自服务器的“Hello, World!”响应。
curl http://localhost:8080
curl -X POST -d "param1=value1¶m2=value2" http://localhost:8080
UDP服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8080
#define BUFFER_SIZE 2048void handle_client(int server_socket, struct sockaddr_in *client_address, socklen_t client_len) {char buffer[BUFFER_SIZE];int bytes_received = recvfrom(server_socket, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)client_address, &client_len);if (bytes_received == -1) {perror("Error receiving data");return;}buffer[bytes_received] = '\0';printf("Received request from %s:%d\n%s\n", inet_ntoa(client_address->sin_addr), ntohs(client_address->sin_port), buffer);char response[] = "Hello, World from UDP!";sendto(server_socket, response, sizeof(response) - 1, 0, (struct sockaddr *)client_address, client_len);
}int main() {int server_socket;struct sockaddr_in server_address, client_address;socklen_t client_len;server_socket = socket(AF_INET, SOCK_DGRAM, 0);if (server_socket == -1) {perror("Could not create socket");exit(1);}server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = INADDR_ANY;server_address.sin_port = htons(PORT);if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {perror("Bind failed");exit(1);}printf("UDP server is running on port %d...\n", PORT);while (1) {client_len = sizeof(client_address);handle_client(server_socket, &client_address, client_len);}close(server_socket);return 0;
}
UDP客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>#define SERVER_PORT 8080
#define BUFFER_SIZE 2048int main(int argc, char *argv[]) {int client_socket;struct sockaddr_in server_address;char buffer[BUFFER_SIZE];// 检查命令行参数if (argc != 2) {printf("Usage: %s <Server IP>\n", argv[0]);exit(1);}client_socket = socket(AF_INET, SOCK_DGRAM, 0);if (client_socket == -1) {perror("Could not create socket");exit(1);}memset(&server_address, 0, sizeof(server_address));server_address.sin_family = AF_INET;server_address.sin_port = htons(SERVER_PORT);if (inet_pton(AF_INET, argv[1], &server_address.sin_addr) <= 0) {perror("inet_pton() failed");exit(1);}// 向服务器发送消息char message[] = "Hello, UDP Server!";sendto(client_socket, message, strlen(message), 0, (struct sockaddr *)&server_address, sizeof(server_address));// 接收来自服务器的响应int bytes_received = recvfrom(client_socket, buffer, BUFFER_SIZE - 1, 0, NULL, NULL);if (bytes_received == -1) {perror("Error receiving data");exit(1);}buffer[bytes_received] = '\0';printf("Received from server: %s\n", buffer);close(client_socket);return 0;
}
或者使用以下命令向UDP服务器发送数据:
echo "Your message here" | nc -u -w1 localhost 8080
为什么 send() 和 recv() 适用于TCP而不是UDP
TCP (Transmission Control Protocol) 是一个面向连接的协议。当我们谈论TCP连接时,我们指的是一个由客户端套接字和服务器套接字组成的持久的网络连接。这意味着,一旦建立了TCP连接,双方都知道对方的IP地址和端口号,因此不需要在每次数据交换时重新指定。
由于这种固定的连接特性,当我们想要通过已经建立的TCP连接发送或接收数据时,不需要再次指定远程的地址和端口。这就是为什么 send() 和 recv() 适用于TCP:它们只发送和接收数据,不涉及地址信息。
另一方面,UDP (User Datagram Protocol) 是一个无连接的协议。这意味着每次数据包的发送都是独立的,没有固定的连接或对端信息与其相关联。因此,当我们使用UDP发送数据时,需要指定要将数据发送到的地址和端口。这就是 sendto() 和 recvfrom() 的用途。
总结:
- TCP是面向连接的,一旦连接建立,系统就知道数据将被发送到哪里,因此只需要
send()和recv()。 - UDP是无连接的,所以每次发送数据都需要指定目的地,这就是为什么需要
sendto()和recvfrom()。
当然,技术上可以为UDP使用 connect() 来设置默认的远程地址和端口,然后使用 send() 和 recv(),但这样做是非典型的,并可能导致与UDP的无连接特性不一致的行为。
当我们说SOCK_STREAM(如TCP)为我们提供了一个连续的字节流,并且没有内在的消息边界,这是什么意思呢?
-
连续的字节流:
- 当我们使用TCP发送数据,是在向一个开放的连接发送一个连续的字节流。例如,如果连续调用三次
send()函数,发送三个字符串,它们可能会被接收端作为一个连续的字节流接收。 - 不存在固定的消息大小或结构,我们可以任意发送任何大小的数据。
- 当我们使用TCP发送数据,是在向一个开放的连接发送一个连续的字节流。例如,如果连续调用三次
-
没有内在的消息边界:
- 在TCP中,数据的发送和接收是流式的,没有固定的消息边界。这意味着,如果发送方连续发送了两个数据块,接收方没有办法仅通过TCP来知道这两个数据块是如何分隔的。接收方可能在一个
recv()调用中接收到两个数据块的部分或全部。 - 例如,如果发送方连续执行两次
send(),分别发送字符串"HELLO"和"WORLD",接收方可能需要多次recv()调用来接收这些数据,或者可能在一个recv()调用中接收到字符串"HELLOWORLD"。
- 在TCP中,数据的发送和接收是流式的,没有固定的消息边界。这意味着,如果发送方连续发送了两个数据块,接收方没有办法仅通过TCP来知道这两个数据块是如何分隔的。接收方可能在一个
这种没有消息边界的特性与SOCK_DGRAM(如UDP)形成了对比,在UDP中,每个sendto()调用发送的数据都被视为一个独立的消息,且在接收端通过一个recvfrom()调用完整地接收。
这就是为什么在使用TCP时,应用程序往往需要自己实现某种消息边界的机制,例如通过使用特定的分隔符、固定长度的头部或其他协议来定义消息的开始和结束。
SOCK_DGRAM 提供了一个有边界的服务。这意味着,当我们使用 SOCK_DGRAM(如UDP)发送一个数据报,接收端会将这个数据报作为一个整体进行处理,不会将它与其他数据报合并或分割。每个 sendto() 调用对应一个完整且单独的消息,该消息在接收端使用一个 recvfrom() 调用完整接收。
换句话说,数据报协议保留了消息边界。例如,如果发送方调用了两次 sendto(),接收方也必须调用两次 recvfrom() 来接收这两条消息。这与 SOCK_STREAM(如TCP)不同,在流式协议中,数据是一个连续的字节流,没有内在的消息边界。
关于curl命令和nc命令的详细介绍以及网络编程中常用的函数说明,读者可移步至以下博客:
Linux- curl命令
Linux中的nc命令
Linux网络编程- recvfrom() & sendto()
Linux- 网络编程初探
相关文章:
Linux网络编程-极简HTTPUDP服务器
HTTP服务器 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h>#define PORT 8080 #define BUFFER_SIZE 2048void handle_client(int client_socket) {char buffer[BUFFER_SIZE];recv(cl…...
虚拟化、容器与Docker基本介绍以及安装部署(Docker 基本管理)
目录 1 Docker 概述 1.1 Docker与虚拟机的区别 1.2 容器在内核中支持2种重要技术 1.3 Docker核心概念 2 安装 Docker 2 Docker 镜像操作 2.1 搜索镜像 2.2 获取镜像 2.3 镜像加速下载 2.4 查看镜像信息 2.4.1 查看下载的镜像文件信息 2.4.2 查看下载到本地的所有镜像…...
Spring Boot中捕获异常错误信息并将其保存到数据库中
Spring Boot中捕获异常错误信息并将其保存到数据库中: 1.创建数据库表: 首先,您需要创建一个用于存储异常信息的数据库表。可以使用SQL脚本或者使用Hibernate实体类来创建表。以下是一个用于存储异常信息的表的示例SQL: CREATE TABLE erro…...
CNN记录】pytorch中flatten函数
pytorch原型 torch.flatten(input, start_dim0, end_dim- 1) 作用:将连续的维度范围展平维张量,一般写再某个nn后用于对输出处理, 参数: start_dim:开始的维度 end_dim:终止的维度,-1为最后…...
科普长文--网络安全拟态防御技术概念及应用
网络安全拟态防御技术概念 什么是网络安全拟态防御? 网络安全拟态防御技术是一种基于生物拟态原理,利用动态异构冗余构造、拟态伪装机制、测不准效应等手段,实现网络空间的主动防御和内生安全的技术。它是由中国工程院院士邬江兴首创的,旨在应对网络空间中的各种未知威胁…...
框架篇
一、Spring中的单例Bean是线程安全的吗 二、AOP相关面试题 三、Spring中的事务 四、Spring中事务失效的场景有 五、Spring bean的生命周期 六、Spring的循环依赖 七、SpringMVC的执行流程 八、自动配置原理 九、Spring框架常见的注解 十、Mybatis的执行流程 十一、MyBatis延迟加…...
Spring MVC(中)
1、Spring MVC视图: SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户 SpringMVC视图的种类很多,默认有转发视图和重定向视图 当工程引入jstl的依赖,转发视图会自动转换为JstlView …...
10月19日,每日信息差
今天是2023年10月19日,以下是为您准备的17条信息差 第一、中国海洋石油遭南向资金净卖出2.38亿港元 第二、阅文集团侯晓楠:网文已经成为中国文化的一张全球名片。据了解,2022年以来,阅文已经在海外上线了自制的300多部动漫影视作…...
【VSCode】解决Open in browser无效
问题描述: 在VSCode中无论是点击右键,选择在默认浏览器中打开,还是按快捷键alt b都没有反应。 解决办法: 右击文件 --> 在文件资源管理器中显示 右击文件,选择属性 点击更改 选择用默认浏览器打开 最后 此时…...
测试饱和了? 大数据测试就业薪资和前景究竟怎么样?
随着不断有转行人员及毕业的大学生进入IT行业,在很多外界人眼里,这个行业的“缺口”已满,人员趋于饱和,但事实真的这样吗?还真没有。只是最基础的岗位需求在慢慢变少了,但行业中比较深的细分岗位࿰…...
DDR3笔记 频率配置
可参考 基于FPGA的DDR3设计(2)DDR3各时钟频率及带宽分析 - 知乎 (zhihu.com) DDR3的时钟频率配置要看两个手册: 1.DDR3器件的手册。 2.开发板芯片的手册 器件 器件名称:MT41J128M16JT-125:K tCK 1.25ns,就可以算出…...
数据结构与算法-(10)---列表(List)
🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如…...
Node-Web模块的用法
题记 node.js中web模块的用法,以下是具体操作过程和代码。 Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL,与客户端的…...
基于TCP的RPC服务
TCP服务器上的RPC,通过创建一个服务器进程监听传入的tcp连接,并允许用户 通过此TCP流执行RPC命令 -module(tr_server). -author("chen"). -behaviour(gen_server).%% API -export([start_link/1,start_link/0,get_count/0,stop/0 ]).-export(…...
docker报错问题解决:Error Invalid or corrupt jarfile app.jar
文章目录 1.问题描述2.问题分析3.问题解决 1.问题描述 此时处在 /home/ubuntu/app 目录下,并且在该目录下有一个 jenkins-0.0.1-SNAPSHOT.jar。 我在 /home/ubuntu/app 目录下执行了 docker 容器运行命令: # 映射 8859 端口 # 容器名为 jenkins-demo #…...
Day 09 python学习笔记
函数 装饰器 回顾内容: 函数可以作为参数进行传递函数可以作为返回值函数名称可以像变量一样进行赋值操作 装饰器:要求记住结论 引入: def play_dnf():print("你好啊,我是赛利亚,今天又是美好的一天")def p…...
力扣labuladong——一刷day02
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣876. 链表的中间结点二、力扣142. 环形链表 II三、力扣160. 相交链表四、力扣141. 环形链表 前言 一、力扣876. 链表的中间结点 /*** Definition for …...
【小白专用23.10.22 已验证】windows 11 安装PHP8.2 +Apache2.4
环境说明 windows:windows 11 x64apache: Apache/2.4.43php :php-8.2.11 一.php 1、PHP下载 PHP For Windows: Binaries and sources Releases 注意: 1.要下载Thread Safe,否则没有php8apache2_4.dll这个文件;如果使用Apache作为服务器…...
Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务
Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务 一. CentOS7 安装配置SFTP服务器详解一、SFTP简介二、关闭防火墙三、安装SSH服务在CentOS7中,sftp只是ssh的一部分,所以采用yum来安装ssh服务即可1. 查看是否已经安装了ssh2.…...
为什么 glBegin 未被定义 未定义的标识符,使用新的 API(LearnOpenGL P2)
文章目录 弃用的 glBegin & glEnd使用新 API 的示例 弃用的 glBegin & glEnd 环境:glfw 3.3.8 glad core OpenGL 初学者在尝试使用 glBegin 和 glEnd 函数来绘制三角形时,有可能找到使用这些函数的文章、代码文献 但许多这些函数已经在OpenG…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
