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

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&param2=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)为我们提供了一个连续的字节流,并且没有内在的消息边界,这是什么意思呢?

  1. 连续的字节流

    • 当我们使用TCP发送数据,是在向一个开放的连接发送一个连续的字节流。例如,如果连续调用三次send()函数,发送三个字符串,它们可能会被接收端作为一个连续的字节流接收。
    • 不存在固定的消息大小或结构,我们可以任意发送任何大小的数据。
  2. 没有内在的消息边界

    • 在TCP中,数据的发送和接收是流式的,没有固定的消息边界。这意味着,如果发送方连续发送了两个数据块,接收方没有办法仅通过TCP来知道这两个数据块是如何分隔的。接收方可能在一个recv()调用中接收到两个数据块的部分或全部。
    • 例如,如果发送方连续执行两次send(),分别发送字符串"HELLO"和"WORLD",接收方可能需要多次recv()调用来接收这些数据,或者可能在一个recv()调用中接收到字符串"HELLOWORLD"。

这种没有消息边界的特性与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.创建数据库表&#xff1a; 首先&#xff0c;您需要创建一个用于存储异常信息的数据库表。可以使用SQL脚本或者使用Hibernate实体类来创建表。以下是一个用于存储异常信息的表的示例SQL&#xff1a; CREATE TABLE erro…...

CNN记录】pytorch中flatten函数

pytorch原型 torch.flatten(input, start_dim0, end_dim- 1) 作用&#xff1a;将连续的维度范围展平维张量&#xff0c;一般写再某个nn后用于对输出处理&#xff0c; 参数&#xff1a; start_dim&#xff1a;开始的维度 end_dim&#xff1a;终止的维度&#xff0c;-1为最后…...

科普长文--网络安全拟态防御技术概念及应用

网络安全拟态防御技术概念 什么是网络安全拟态防御? 网络安全拟态防御技术是一种基于生物拟态原理,利用动态异构冗余构造、拟态伪装机制、测不准效应等手段,实现网络空间的主动防御和内生安全的技术。它是由中国工程院院士邬江兴首创的,旨在应对网络空间中的各种未知威胁…...

框架篇

一、Spring中的单例Bean是线程安全的吗 二、AOP相关面试题 三、Spring中的事务 四、Spring中事务失效的场景有 五、Spring bean的生命周期 六、Spring的循环依赖 七、SpringMVC的执行流程 八、自动配置原理 九、Spring框架常见的注解 十、Mybatis的执行流程 十一、MyBatis延迟加…...

Spring MVC(中)

1、Spring MVC视图&#xff1a; SpringMVC中的视图是View接口&#xff0c;视图的作用渲染数据&#xff0c;将模型Model中的数据展示给用户 SpringMVC视图的种类很多&#xff0c;默认有转发视图和重定向视图 当工程引入jstl的依赖&#xff0c;转发视图会自动转换为JstlView …...

10月19日,每日信息差

今天是2023年10月19日&#xff0c;以下是为您准备的17条信息差 第一、中国海洋石油遭南向资金净卖出2.38亿港元 第二、阅文集团侯晓楠&#xff1a;网文已经成为中国文化的一张全球名片。据了解&#xff0c;2022年以来&#xff0c;阅文已经在海外上线了自制的300多部动漫影视作…...

【VSCode】解决Open in browser无效

问题描述&#xff1a; 在VSCode中无论是点击右键&#xff0c;选择在默认浏览器中打开&#xff0c;还是按快捷键alt b都没有反应。 解决办法&#xff1a; 右击文件 --> 在文件资源管理器中显示 右击文件&#xff0c;选择属性 点击更改 选择用默认浏览器打开 最后 此时…...

测试饱和了? 大数据测试就业薪资和前景究竟怎么样?

随着不断有转行人员及毕业的大学生进入IT行业&#xff0c;在很多外界人眼里&#xff0c;这个行业的“缺口”已满&#xff0c;人员趋于饱和&#xff0c;但事实真的这样吗&#xff1f;还真没有。只是最基础的岗位需求在慢慢变少了&#xff0c;但行业中比较深的细分岗位&#xff0…...

DDR3笔记 频率配置

可参考 基于FPGA的DDR3设计&#xff08;2&#xff09;DDR3各时钟频率及带宽分析 - 知乎 (zhihu.com) DDR3的时钟频率配置要看两个手册&#xff1a; 1.DDR3器件的手册。 2.开发板芯片的手册 器件 器件名称&#xff1a;MT41J128M16JT-125:K tCK 1.25ns&#xff0c;就可以算出…...

数据结构与算法-(10)---列表(List)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…...

Node-Web模块的用法

题记 node.js中web模块的用法&#xff0c;以下是具体操作过程和代码。 Web服务器一般指网站服务器&#xff0c;是指驻留于因特网上某种类型计算机的程序&#xff0c;Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL&#xff0c;与客户端的…...

基于TCP的RPC服务

TCP服务器上的RPC&#xff0c;通过创建一个服务器进程监听传入的tcp连接&#xff0c;并允许用户 通过此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 目录下&#xff0c;并且在该目录下有一个 jenkins-0.0.1-SNAPSHOT.jar。 我在 /home/ubuntu/app 目录下执行了 docker 容器运行命令&#xff1a; # 映射 8859 端口 # 容器名为 jenkins-demo #…...

Day 09 python学习笔记

函数 装饰器 回顾内容&#xff1a; 函数可以作为参数进行传递函数可以作为返回值函数名称可以像变量一样进行赋值操作 装饰器&#xff1a;要求记住结论 引入&#xff1a; def play_dnf():print("你好啊&#xff0c;我是赛利亚&#xff0c;今天又是美好的一天")def p…...

力扣labuladong——一刷day02

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣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 注意&#xff1a; 1.要下载Thread Safe&#xff0c;否则没有php8apache2_4.dll这个文件&#xff1b;如果使用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 环境&#xff1a;glfw 3.3.8 glad core OpenGL 初学者在尝试使用 glBegin 和 glEnd 函数来绘制三角形时&#xff0c;有可能找到使用这些函数的文章、代码文献 但许多这些函数已经在OpenG…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

Windows 下端口占用排查与释放全攻略

Windows 下端口占用排查与释放全攻略​ 在开发和运维过程中&#xff0c;经常会遇到端口被占用的问题&#xff08;如 8080、3306 等常用端口&#xff09;。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口&#xff0c;帮助你高效解决此类问题。​ 一、准…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析

目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork&#xff08;创建个人副本&#xff09;步骤 2: Clone&#xff08;克隆…...