【Linux网络编程】服务端编程初体验

news2025/1/10 20:37:20

文章目录

  • 前言
  • 服务端是啥、有什么特点
  • 核心函数
  • socket的简介
  • 服务器编程
  • 客户端代码
  • The End


前言

在上节课(Linux网络编程初体验)中我们实现了连接bilibili的功能,并获取其html源码在这里插入图片描述
如图所示.
今天我们要自己编写个服务端来服务我们的客户端


提示:以下是本篇文章正文内容,下面案例可供参考

服务端是啥、有什么特点

服务端长期暴露于网络,并等待客户端连接
特点:
服务端无法主动连接客户端
客户端只能按照预定义的方式连接服务端

服务端编程模式:

socket()->bind()->listen()->accept()->client_sock->
send()/recv->close()

核心函数

int bind(int sock,struct sockaddr*addr,socklen_t addrlen);//参数1:服务端sock,参数2:服务端sockaddr,参数3:参数2的大小,类型为socklen_t
int listen(int sock,int backlog);//参数1:服务端sock,参数2:直接填1
int accept(int sock,struct sockaddr*addr,socklen_t*addrlen);//参数1:客户端sock,参数2接受客户端addr的地址,参数3:参数2的长度

accept()的返回值为客户端的sock

socket的简介

服务端socket只用于连接,不进行通讯
服务端的socket用于产生客户端的socket

socket还可以提供不同类型的通信功能(本地、局域网等)

服务器编程

头文件:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

定义服务端的socket和sockaddr_inint server = 0; struct sockaddr_in saddr = {0};
定义要通信的客户端的socket和sockaddr_inint client = 0; struct sockaddr_in caddr = {0};
定义客户端sockaddr_in 的长度变量socklen_t asize = 0;
以及其他的变量

	int len = 0;//发送和接收的字符串长度
    char buf[32] = {0};//接收区
    int r = 0;//循环控制变量

创建socket

	server = socket(PF_INET, SOCK_STREAM, 0);

    if( server == -1 )
    {
        printf("server socket error\n");
        return -1;
    }

赋值服务端的sockaddr_in

	saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:同一wifi下的主机地址都可以
    saddr.sin_port = htons(8899);

绑定以及监听

	if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
    {
        printf("server bind error\n");
        return -1;
    }

    if( listen(server, 1) == -1 )
    {
        printf("server listen error\n");
        return -1;
    }

等待客户端的连接


	while(1)
	{
		asize = sizeof(caddr);//客户端sockaddr_in大小

    	client = accept(server, (struct sockaddr*)&caddr, &asize);

    	if( client == -1 )
    	{
   	       printf("client accept error\n");
     	   return -1;
    	}
	
		printf("client: %d\n", client);
	}

接收和发送数据:

		do
        {
            r = recv(client, buf, sizeof(buf), 0);

            if( r > 0 )
            {
                printf("Receive: %s\n", buf);

                if( strcmp(buf, "quit") != 0 )//当字符串为quit时,退出
                {
                    len = send(client, buf, r, 0);
                    break;
                }
                else
                {
                    break;
                }
            }

        } while ( r > 0 );

注意:这里的代码在while(1)里面

代码全貌:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int server = 0;
    struct sockaddr_in saddr = {0};
    int client = 0;
    struct sockaddr_in caddr = {0};
    socklen_t asize = 0;
    int len = 0;server
    char buf[32] = {0};
    int r = 0;

    server = socket(PF_INET, SOCK_STREAM, 0);

    if( server == -1 )
    {
        printf("server socket error\n");
        return -1;
    }

    saddr.sin_fami0ly = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8888);

    if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
    {
        printf("server bind error\n");
        return -1;
    }

    if( listen(server, 1) == -1 )
    {
        printf("server listen error\n");
        return -1;
    }

    printf("server start success\n");

    while( 1 )
    {
        asize = sizeof(caddr);

        client = accept(server, (struct sockaddr*)&caddr, &asize);

        if( client == -1 )
        {
            printf("client accept error\n");
            return -1;
        }

        printf("client: %d\n", client);

        do
        {
            r = recv(client, buf, sizeof(buf), 0);

            if( r > 0 )
            {
                printf("Receive: %s\n", buf);

                if( strcmp(buf, "quit") != 0 )
                {
                    len = send(client, buf, r, 0);
                    break;
                }
                else
                {
                    break;
                }
            }

        } while ( r > 0 );

        close(client);
    }
    
    close(server);

    return 0;
}

客户端代码

复用上期的服务端
改动:
1、定义input变量,让用户自己输入字符发送给服务端char input[32] = {0};
2、端口号和ip地址
ip地址:在TerMinal中输入ifconfig可以看到ip地址。如下图
在这里插入图片描述
端口号:要和服务器中的一样(8899)

收发数据代码:

	while(1)
	{
			printf("Input: ");

        	scanf("%s", input);

        	len = send(sock, input, strlen(input) + 1, 0);

        	r = recv(sock, buf, sizeof(buf), 0);

        	if( r > 0 )
        	{
            	printf("Receive: %s\n", buf);
        	}
       		else
        	{
          		break;
        	}
        }

客户端代码全貌:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int sock = 0;
    struct sockaddr_in addr = {0};
    int len = 0;
    char buf[128] = {0};
    char input[32] = {0};
    int r = 0;

    sock = socket(PF_INET, SOCK_STREAM, 0);

    if( sock == -1 )
    {
        printf("socket error\n");
        return -1;
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("192.168.254.128");
    addr.sin_port = htons(8899);

    if( connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 )
    {
        printf("connect error\n");
        return -1;
    }

    printf("connect success\n");

    while( 1 )
    {
        printf("Input: ");

        scanf("%s", input);

        len = send(sock, input, strlen(input) + 1, 0);

        r = recv(sock, buf, sizeof(buf), 0);

        if( r > 0 )
        {
            printf("Receive: %s\n", buf);
        }
        else
        {
            break;
        }
    }

    close(sock);

    return 0;
}

The End

大家可以使用下面2个命令编译我们写好的东西:

gcc -o 编译后的文件名.o 编译的文件名.c
./编译后的文件名.o

注意:要先开服务端!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SGI STL 二级空间配置源码刨析

文章目录内存分配第二级配置器空闲链表的设计内存申请代码内存释放代码注意内存分配 当我们new一个对象时&#xff0c;实际做了两件事情&#xff1a; 使用malloc申请了一块内存。执行构造函数。 在SGI中&#xff0c;这两步独立出了两个函数&#xff1a;allocate申请内存&…

年产20吨鸡枞菌产品的生产工艺设计(lunwen+课题登记表+cad图纸)

目录 摘 要 1 Abstract 2 一、设计任务和内容 4 1.1 设计题目 4 1.2 设计原始数据 4 二、设计说明 5 2.1 全厂总平面布置 5 2.1.1 原料厂及堆场 5 2.1.2 生产区 5 2.1.3 厂前区 6 2.1.4 动力区 6 2.1.5 辅助车间 6 2.1.6 仓库区 6 2.2 三废的处理及回收 6 2.3 车间布置说明 6 三…

Request和Response基础知识入门

文章目录1&#xff0c;Request和Response的概述2&#xff0c;Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 获取请求参数的通用方式2.3 IDEA快速创建Servlet2.4 请求参数中文乱码问题2.4.1 POST请…

【Unity3D】绘制物体表面三角形网格

1 仅绘制三角形网格 1&#xff09;创建游戏对象 创建一个空对象&#xff0c;重命名为 Grid&#xff0c;并在其下添加需要绘制网格的对象&#xff0c;如下&#xff1a; 场景显示如下&#xff1a; 2&#xff09;添加脚本组件 GridController.cs using System; using UnityEngin…

JavaWeb_第4章_RequestResponse

JavaWeb_第4章_Request&Response 文章目录JavaWeb_第4章_Request&Response1&#xff0c;Request和Response的概述2&#xff0c;Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 获取请求参数…

【ceph】分布式存储ceph

1 块存储&#xff0c;文件存储&#xff0c;对象存储 1.1 简介 文件存储&#xff1a;分层次存储&#xff0c;文件存储在文件夹中&#xff1b;访问文件时系统需要知道文件所在的路径。 举例&#xff1a;企业部门之间运用网络存储器&#xff08;NAS&#xff09;进行文件共享。 …

把握出租车行驶的数据脉搏 :出租车轨迹数据给你答案!

城市化带来的道路拥堵、出行耗时长等交通问题给交管部门带来了巨大的挑战。 ▼ 通过安装在出租车上的GPS设备&#xff0c;可以采集到大量的轨迹数据&#xff0c;从而帮助我们分析人们出行信息&#xff0c;达到优化交通的目的。 最近我们被客户要求撰写关于出租车行驶的研究报…

一次性分清zip、gzip、bzip2、tar命令

文章目录归类zip与unzip命令tar命令使用方式zipunzipgzipgunzipbzip2bunzip2tar归类 我们把这几个命令归类为几种能力&#xff0c;一个是解压缩能力一个是打拆包能力。 我这里打包的意思是不使用压缩算法对文件进行压缩&#xff0c;只是简单的把多个文件归档为一个文件。而拆包…

Qt OpenGL(二十五)——Qt OpenGL 核心模式-Qt封装的函数实现彩色三角形

Qt OpenGL(二十五)——Qt OpenGL 核心模式-Qt封装的函数实现彩色三角形 上一篇文章我们绘制了彩色的三角形,接下来其实就应该是让这个三角形旋转起来了,但是,旋转起来之前,还是想通过Qt自己的封装类实现彩色的三角形,并且让他旋转起来。 这才我(冯一川)是写这个系列…

编程之美4 Nim游戏

Tag&#xff1a;贪心&#xff1b;动态规划 题目 N块石头排成一行&#xff0c;每块石头有各自固定的位置。两个玩家依次取石头&#xff0c;每个玩家每次可以取其中任意一块石头&#xff0c;或者相邻的两块石头&#xff0c;石头在游戏过程中不能移位&#xff08;即编号不会改变…

在ASF中使用On Demand生产DEM等产品时使用不同参考DEM的区别

在ASF中使用On Dmand生产DEM等产品时使用不同参考DEM 主要有两种DEM&#xff0c;分别是SRTM和COP-DEM&#xff08;GLO-30&#xff09; 当我们添加Dmand进程之后&#xff0c;点击On Demand Queue 然后进入On Demand界面&#xff08;如下图所示&#xff09; 在Processing Op…

MySQL主从复制介绍及实操演示

1. 基本概念 MySQL主从复制的主要效果简单来说是将两个单独的数据库服务器关联起来&#xff0c;对于主机&#xff08;Master&#xff09;以及从机&#xff08;Slave&#xff09;&#xff0c;从机的数据会伴随着主机数据的变化而同步 2. 主从复制作用 可以解决单个MySQL数据库…

leetcode 63. 不同路径 II

文章目录题目思考代码和注释总结题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑…

Android WorkManager使用介绍

一、引言 WorkManager 是google提供的异步执行任务的管理框架&#xff0c;是 Android Jetpack 的一部分&#xff0c;会根据手机的API版本和应用程序的状态来选择适当的方式执行任务。   在后台执行任务的需求是非常常见的&#xff0c;Android也提供了多种解决方案&#xff0c…

高阶数据结构:并查集

本篇主要是介绍并查集的内容&#xff1a;所谓并查集就是一种描述不相交集合的数据结构&#xff0c;即若一个问题涉及多个元素&#xff0c;它们可以划分到不同集合&#xff0c;同属一个集合内的元素等价&#xff0c;不同集合内的元素不等价。 文章目录 一、并查集原理二、并查集…

Prophet在R语言中进行时间序列数据预测

您将学习如何使用Prophet&#xff08;在R中&#xff09;解决一个常见问题&#xff1a;预测公司明年的每日订单。 最近我们被客户要求撰写关于时间序列的研究报告&#xff0c;包括一些图形和统计输出。 数据准备与探索 Prophet最适合每日数据以及至少一年的历史数据。 我们将…

Ansible

Ansible是什么&#xff1f; Ansible是一个基于eythn开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pbet和Saltstack能实现的功能&#xff0c;As;ble基本上都可以实现。Ansible能批量配置、部署、管理上…

MongoDB入门与实战-第五章-MongoDB副本集

目录参考一、副本集概念1、**主要功能**2、主从复制和副本集区别3、复制结构图二、副本集成员角色1.主节点2.副本节点3.仲裁节点三、副本集架构&#xff08;一主一副本一仲裁&#xff09;1、**设置读操作权限&#xff1a;**2、取消作为奴隶节点的读权限四、选举原则1、触发条件…

时序逻辑电路

数字电路分为两大类&#xff0c;组合逻辑电路和时序逻辑电路 今天我们要开始学习的是时序逻辑电路&#xff0c;要求大家掌握 同步逻辑电路的分析方法 常用的时序逻辑电路的使用方法 当然由于时序逻辑电路的特点&#xff0c;使得时序逻辑电路难度远远大于组合逻辑电路 电路任…

一文详解Redis键过期策略,最全文档

文章目录1 设置带过期时间的 key1.1 刷新过期时间1.2 Redis 之前的 2.1.3 的差异1.3 返回值1.4 示例1.5 带过期时间的 key1.6 过期精度1.7 过期和持久化2 Redis的key过期策略2.1 惰性删除2.1.1 优点2.1.2 缺点定时删除优点缺点2.2 定期删除优点缺点难点定期删除流程Redis采用的…