Linux-----网络套接字编程

news2025/7/28 6:01:45

文章目录

    • 铺垫一下概念知识
    • 基于UDP协议下的套接字编程
    • 基于TCP协议下的套接字编程

铺垫一下概念知识

我们知道IP地址是用来标识主机唯一性的。
而源IP地址表示从哪个主机来, 目的IP地址表示去哪个主机。

端口号(port):
1,标识进程唯一性的。也就是说,一个端口号用来标识一个进程。
2,端口号是一个2字节16位的整数。

同样的:多个端口号可以对应一个进程, 多个进程不能对应一个端口。
因为必须通过端口号找到唯一一个进程。
IP地址 + 端口号(port) 就可以表示互联中的一台主机中的一个进程。

源端口号和目的端口号:传输层的数据段中有两个端口号,分别叫做目的端口号和源端口号,表示数据是发给哪个进程,
由哪个进程发的

我们知道,网络通信的本质就是进程间通信。
在这里插入图片描述

TCP协议:
1,传输层协议
2,有链接
3,可靠
4,面向字节流(数据从一方流向另一方)。

UDP协议
1,传输层协议
2,无连接
3,不可靠
4,面向数据报。

这里的可靠和不可靠是中性词,可靠肯定是要更多资源去维护的。如银行取钱那肯定是要可靠的。
其他的不一定要可靠。

网络字节序的概念:
其实在内存中分大小端。
小端:数据的低位存放在低地址
大端:数据的低位存放在高地址

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

网络字节序和主机字节序的相关转换函数:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

h----host主机, n-----network网络。

基于UDP协议下的套接字编程

UDP协议下的相关函数操作
在这里插入图片描述

服务端:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>

#include <netinet/in.h>  //这两个头文件是 struct sockaddr_in
#include <arpa/inet.h>

using namespace std;


void Usage(const char* proc)
{
   cout << "Usage:" << endl << "./server  " << "server.port";
}

//   ./server server.port
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
       Usage(argv[0]);
       return 1;
    }

    //1 创建套接字(网络文件), sock---文件描述符
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock < 0)
    {
        cout << "sock fail" << endl;
        return 2;
    }

    //2  bind   绑定ip地址和端口号port
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[1]));
    local.sin_addr.s_addr = INADDR_ANY;  //服务端可以任意绑定

    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        cout << "bind fail" << endl;
        return 3;
    }

    //提供服务
    char buff[1024];
    while(1)
    {
         struct sockaddr_in peer;
         memset(&peer, 0 , sizeof(peer));
         socklen_t len = sizeof(peer);
          
        //peer 返回的客户端的ip + 端口号的属性集合 sockaddr
         ssize_t s = recvfrom(sock, buff, sizeof(buff) , 0, (struct sockaddr*)&peer, &len);
         if(s > 0)
         {
            //成功接受
            buff[s] = 0;
            cout << "clinet #" << buff << endl;

            const char* ch = "我是服务器, 你好啊";
            sendto(sock, ch, strlen(ch), 0, (struct sockaddr*)&peer, len);
         }
         else
         {
             cout << "recvfrom fail" << endl;
             return 3;
         }
    }

    return 0;
}

客户端:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>

#include <netinet/in.h>  //这两个头文件是 struct sockaddr_in
#include <arpa/inet.h>
using namespace std;

void Usage(const char* proc)
{
    cout << "Usage" << endl << proc << "server.ip  server.port" << endl; 
}

// ./client   server.ip   server.port
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }

    //1 创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock < 0)
    {
        cout << "sock fail" << endl;
        return 1;
    }

    //不需要绑定,OS会自动绑定
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));      //端口号
    server.sin_addr.s_addr = inet_addr(argv[1]); //ip
     
    while(1)
    {
        cout << "client:" ;
        char line[1024];
        cin >> line;
        sendto(sock, line, sizeof(line), 0, (struct sockaddr*)&server, sizeof(server));
        
        //ret 占位用,无其他作用
        struct sockaddr_in ret;
        socklen_t len = sizeof(ret);
        char buff[1024];
        ssize_t s = recvfrom(sock, buff, sizeof(buff), 0, (struct sockaddr*)&ret, &len);
        if(s < 0)
        {
             cout << "client recvfron fail" << endl;
             return 4;
        }

        cout << "server say" << buff << endl << endl;;
    }
    return 0;
}

基于TCP协议下的套接字编程

相关操作函数的总结:
1,创建socket的过程,socket()本质是创建网络文件,与系统相关
2,bind() sockaddr_in ----> 填入ip + port 本质是将ip + port 与网络文件相关联
3, listen() 设置该socket文件的状态,允许客户端来链接我
4 ,accept() 获取新连接到应用层,以文件描述符为代表,OS中肯定会存在大量的链接,如何管理呢?—>先描述,再组织
5, read/write 本质就是进行网络通信,而对于用户来说,就是在进行文件的正常读写。
6, close() ,关闭文件, 系统层面上,释放曾经申请的文件资源和链接资源
7, connect() 本质是发起链接, 在系统层面上,构建一个报文发过去。

客户端:

#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <signal.h>
#include <pthread.h>
#include <sys/wait.h>
using namespace std;

void Usage(const char* proc)
{
     cout << "Usage:" << endl << proc << "   port" << endl;   
}

void ServerIO(int new_sock)
{
        //开始服务
         while(1)
         {
             char buff[1024];
             memset(buff, 0, sizeof(buff));

             ssize_t s = read(new_sock, buff, sizeof(buff));
             if(s > 0)
             {
                 cout << "client say#" << buff << endl;

                 const char* ch = "server recv";
                 write(new_sock, ch, strlen(ch));
             }
             else if(s == 0)
             {
                //对端关闭
             }
             else
             {
                cout << "new_sock fail " << endl;
                return ;
             }
         }

}

void* handler(void* args)
{
    int* p = (int*)args;
    pthread_detach(pthread_self());
    ServerIO(*p);
    close(*p);
}

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    
    //1, 创建套接字(网络文件) , AF_INFT是ipv4, sock_stream 是面向字节流
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        cout << "sock fail" << endl;
        return 2;
    }

    //2 bind
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[1]));
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        cout << "bind error" << endl;
        return 3;
    }

    //3  监听
    if(listen(sock,5) < 0)
    {
        cout << "listen fail" << endl;
        return 4;
    }

    //4 提供服务
    while(1)
    {
         struct sockaddr_in peer;
         socklen_t len = sizeof(peer);
         
         //new sock 是提供服务的套接字, sock是用于监听的套接字
         //          提供服务               在线拉客
         int new_sock = accept(sock, (struct sockaddr*)&peer, &len);
         if(new_sock < 0)
         {
            continue;
         }
         
         
         //通过创建进程来实现可对多个客户同时来进行服务
         /*signal(SIGCHLD, SIG_IGN);
         pid_t id = fork();
         if(id == 0)
         {
            //子进程关闭与自己无关的文件描述符
             close(sock);
             ServerIO(new_sock);
             close(new_sock);
         }
         else if(id < 0)
         {
            return 7;
         }
         else
         {
            //panrent
         }
         */
         
         //通过创建线程的方式来实现对多个客户同时进行服务
         pthread_t tid;
         int* pram = new int(new_sock);
         pthread_create(&tid, nullptr, handler, pram);
    }

    return 0;
}

用户端:

#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
using namespace std;

void Usage(const char* proc)
{
     cout << "Usage:" << endl << proc << "   port" << endl;   
}

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    
    //1, 创建套接字(网络文件) , AF_INFT是ipv4, sock_stream 是面向字节流
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        cout << "sock fail" << endl;
        return 2;
    }

    //2 bind
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[1]));
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        cout << "bind error" << endl;
        return 3;
    }

    //3  监听
    if(listen(sock,5) < 0)
    {
        cout << "listen fail" << endl;
        return 4;
    }

    //4 提供服务
    while(1)
    {
         struct sockaddr_in peer;
         socklen_t len = sizeof(peer);
         
         //new sock 是提供服务的套接字, sock是用于监听的套接字
         //          提供服务               在线拉客
         int new_sock = accept(sock, (struct sockaddr*)&peer, &len);
         if(new_sock < 0)
         {
            continue;
         }

         //开始服务
         while(1)
         {
             char buff[1024];
             memset(buff, 0, sizeof(buff));

             ssize_t s = read(new_sock, buff, sizeof(buff));
             if(s > 0)
             {
                 cout << "client say#" << buff << endl;

                 const char* ch = "server recv";
                 write(new_sock, ch, strlen(ch));
             }
             else if(s == 0)
             {
                //对端关闭
             }
             else
             {
                cout << "new_sock fail " << endl;
                return 6;
             }
         }
    }

    return 0;
}

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

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

相关文章

C++之继承、派生

目录 1.继承的概念与定义 2.层次概念是计算机的重要概念: 3.私有的能被继承&#xff0c;不能被访问 4.继承的三步骤 1.继承语法 2.继承例子 5.有继承和组合的构造顺序---内存布局 6.继承之下的赋值运算符重载 1.基础知识 2.Person、Student例子 7.一个类被多个类继承 …

22.11.18打卡 [传智杯 #3 初赛] 部分题

森林图论懒得写, 等搞完dp之后再来复习图论, 还有一题数据有问题没写 [传智杯 #3 初赛] 课程报名 - 洛谷 哇真的签到, 第一眼还想着推公式呢, 看这数据范围直接暴力了 /* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿…

LiveGBS/LiveNVR组合实现GB35114平台端和GB35114设备端的GB35114的交互流程

概述&#xff1a; GB35114是在GB28181基础上扩展而来&#xff0c;增加了身份认证和数据加密。LiveNVR设备通过GB35114注册到LiveGBS时&#xff0c;LiveGBS平台端需要校验LiveNVR设备的身份&#xff0c;这是单向认证。同时可选LiveNVR也检验LiveGBS平台的身份&#xff0c;如果互…

[Howto] Pytorch Window GPU 环境配置

注&#xff1a; how to 系列只有基本的操作&#xff0c;不涉及原理&#xff0c;类似于操作手册。 Linux&#xff0c;MacOS和Window配置方法差不多&#xff0c;就是环境变量的修改方式不太一样&#xff0c;就不单独说明了。 1. 确定Pytorch版本 估计像我一样的初学者&#xf…

关于commonjs、AMD、UMD、ESM以及ts模块之间的使用差异

commonjs 特点&#xff1a;一个文件就是一个模块&#xff0c;拥有独立的作用域&#xff0c;适用于服务端不适合浏览器端。导出模块内部数据通过module.exports或exports对象默认导出&#xff1a; // true const a 1 const b 2 module.exports {a, b }或者 // true const …

【跨境电商卖家】Instagram营销初学者指南(二):方法与技巧

关键词&#xff1a;跨境电商卖家、instagram营销 1.为 Instagram营销设定目标 在你开始在 Instagram 上发帖之前&#xff0c;问问你自己&#xff08;或你的团队&#xff09;一件事&#xff1a;你为什么在 Instagram 上&#xff1f;尽管该平台很受欢迎&#xff0c;但您的回答不…

linux笔记(6):东山哪吒D1H显示HDMI测试-命令行调试

文章目录1.测试流程和结果2.测试过程详解2.1 挂载测试工具1.2 设置参数1.2.1设置name1.2.2选择命令1.2.3 设置命令参数1.3开启显示3.还没搞清楚怎么在应用中显示字符测试开发板的HDMI输出。 参考文档&#xff1a;全志官方文档。 1.测试流程和结果 测试结果&#xff1a; 2.测…

如何实现一键全选

利用复选框的激活、非激活实现一键全选功能 效果展示 前置准备 投票列表素材 具体步骤 添加素材 制作列表复选框 制作一件全选按钮 创建复选框相关行为触发器 制作一键全选触发器 步骤分解 添加素材 拖拽 图片组件 到 根容器 选中 图片组件 铺满父级容器 点击 检查面板 中的 …

一种新的群体智能优化算法:麻雀搜索算法(SSA)(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

C++中函数调用的整个过程内存堆栈分配详解

函数调用过程中&#xff1a;实参将值拷贝给函数的形参&#xff0c;而函数的形参相当于一个生存周期位于函数 内部的局部变量&#xff0c;函数内部的内存操作也只是将拷贝到形参的值进行操作&#xff0c;形参在函数结束 后会被栈自动回收释放(形参在栈中分配)&#xff0c;这就是…

Spring Security如何防止会话固定攻击

在春季安全课程的这篇文章中&#xff0c;我们将研究春季安全会话固定以及如何防止春季应用程序中的会话劫持。 春季安全会话固定 会话固定是一种非常常见且最常见的攻击类型&#xff0c;恶意攻击者可以通过访问站点来创建会话&#xff0c;然后诱使其他用户使用相同的会话登录…

副业是刚需?分享几个程序员接外包私活的网站

经常看到某某程序员接了个项目开发&#xff0c;工作之余轻轻松松赚了钱还顺带提升了技术&#xff1b;或者看到某大佬又发表了一篇程序员技术提升稿件&#xff0c;阅读点赞收藏三连发&#xff0c;这个月的零花钱又不愁了...但自己只是一名普普通通的程序员&#xff0c;能找到这样…

Golang入门笔记(10)—— 闭包 closure

先看一段代码&#xff0c;脱离代码讲闭包&#xff0c;太干了。 package mainimport "fmt"func main() {a : Adder()fmt.Println(a(1))fmt.Println(a(2))fmt.Println(a(3)) }func Adder() func(int) int { // 累加器&#xff1a;这里从10开始累加var sum int 10retu…

linux时区相关

背景&#xff1a;用linux自带的时间接口函数读取时间的时候&#xff0c;发现有时候时间与北京时间不符合&#xff0c;经过研究发现&#xff1a;时间 UTC时间时区带来的偏移。操作方法&#xff1a;timedatectl list-timezones可看支持的时区改时区方法有如下两种&#xff1a; l…

【LeetCode 每日一题】15. 三数之和

01 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元…

【数据结构】链表LinkedList

1.ArrayList的缺陷 2.单链表的实现 3.LinkedList的使用&#xff08;模拟实现&#xff09; 我们之前介绍过ArrayList了&#xff0c;它的底层是数组&#xff0c;数组是一段连续的空间&#xff0c;当我们想要插入或者删除数据的时候&#xff0c;插入元素&#xff0c;就要让插入位置…

用树莓派PICO做一个桌面时钟超详细教程!

用树莓派PICO做一个可显示时间和温湿度的桌面时钟一、概述二、材料准备1、树莓派PICO2、DHT11温湿度传感器3、DS1302时钟模块&#xff08;选用&#xff09;4、SSD1306屏幕5、其他材料三、开始1、连线2、写程序&#xff08;1&#xff09;使用内置RTC函数实现的时钟&#xff08;2…

2.11 教你一套怎么建立自己的选题素材库的方法【玩赚小红书】

一、自身定位延伸选题库 建立选题库&#xff0c;前提先确定自身定位&#xff0c;然后发散性思维延展。如我们做母婴博主&#xff0c;接下来就要想&#xff0c;母婴用户会关注什么&#xff0c;自然会想到到宝宝吃喝玩乐、妈妈保养、产后修复、婆媳关系等等内容。若我们只做宝宝…

这才是,真彩虹预染蛋白Markers

做WB的小伙伴都知道&#xff0c;现市面上各种“多彩”Marker的产品有很多&#xff0c;但是真正拿到手上的&#xff0c;可能是各种各样的&#xff08;见图1&#xff09;&#xff0c;咱也不清楚哪个是真的... 现在小编告诉你&#xff0c;经典的彩虹Marker长这样(见图2)&#xff1…

WebDAV之葫芦儿·派盘+读出通知

读出通知 支持webdav方式连接葫芦儿派盘。 手机各种推销通知太多,如何避免那些繁琐的通知内容,做出一键就能够阅读重要通知的最佳体验,帮助您更加快速和便捷的体验到那些应用内容?推荐大家使用读出通知。 读出通知APP可以设置接收通知的app,还可以用耳机操作,操作简单…