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

Linux:网络套接字

 

理解源IP地址和目的IP地址

在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址.

思考: 我们光有IP地址就可以完成通信了嘛? 想象一下发qq消息的例子, 有了IP地址能够把消息发送到对方的机器上, 但是还需要有一个其他的标识来区分出, 这个数据要给哪个程序进行解析

端口号

端口号(port)是传输层协议的内容.

端口号是一个2字节16位的整数;

端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;

IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;

一个端口号只能被一个进程占用.

另外, 一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定

网络套接字

套接字 = IP + 端口

网络通信的本质:
其实就是进程间通信! !

真正通信的不是这两个机器 !
其实是这两台机器上面的软件(人)
数据有IP(公网)标识一台唯一的主机
用谁来标识各自主机上客户或者服务进程的唯一性呢 ?

为了更好的表示一台主机上服务进程的唯一性,我们采用端口号port
标识服务器进程,客户端进程的唯一性!
ip地址(主机全网唯一性)+ 该主机上的端口号,标识该服务器上进程的唯一性

套接字用来标识全网中唯一的一个进程。

socket 常见API 

TCP协议 

传输层协议

有连接

可靠传输

面向字节流

UDP协议

传输层协议

无连接

不可靠传输

面向数据报

网络字节序

发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;

接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;

因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.

不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;

如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络 字节序和主机字节序的转换

 

netstat -nuap查看端口使用情况。

UDP通信小程序 

udpServer.hpp

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

using namespace std;

namespace szg
{
    string default_ip = "0.0.0.0";
    class udpServer
    {
    public:
        udpServer(uint16_t port, string ip = default_ip)
        :_ip(ip)
        ,_port(port)
        {
            //创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if(_sockfd == -1)
            {
                cout << "socket failed !!!!" << endl;
                exit(1);
            }
            cout << "socket sucess :" << _sockfd << endl;
        }

        void server_init()
        {
            //绑定套接字
            sockaddr_in tmp;
            bzero(&tmp, sizeof(tmp));
            tmp.sin_family = AF_INET;
            tmp.sin_port = htons(_port);//用户端字节序转网络字节序
            tmp.sin_addr.s_addr = inet_addr(_ip.c_str());//IP地址点十进制转32位大端
            cout << "port :" << _port << "    ip :" << _ip << endl;
            int rb = bind(_sockfd, (sockaddr*)&tmp, sizeof(tmp));
            if(rb == -1)
            {
                cout << " bind fail !!!" << endl;
                exit(2);
            }
        }

        void server_start()
        {
            char buffer[1024];
            sockaddr_in peer;
            while(_quit)
            {
                socklen_t len = sizeof(peer);
                //cout << "准备读取" << endl;
                ssize_t rrec = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&peer, &len);
                if(rrec == 0)
                {
                    cout << "receive fail !!!" << endl;
                }
                buffer[rrec] = 0;
                cout << inet_ntoa(peer.sin_addr) << "[" << ntohs(peer.sin_port) << "] : " << buffer << endl;//inet_ntoa大端序列32位转点十进制
            }
        }

        ~udpServer()
        {}
    private:
        string _ip;
        uint16_t _port;
        int _sockfd;
        bool _quit = true;
    };



}

udpServer.cc

#include"udpServer.hpp"
#include<memory>

int main(int args, char* argv[])
{
    if(args != 2)
    {
        cout << "udpServer init fail : \n\t" << argv[0] << "portn\n\n";
        exit(3);
    }
    unique_ptr<szg::udpServer> server(new szg::udpServer((uint16_t)atoi(argv[1])));
    server->server_init();
    server->server_start();

    return 0;

}

udpClient.hpp

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

namespace szg
{
    class udpClient
    {
    public:
        udpClient(string ip, uint16_t port)
        :_ip(ip)
        ,_port(port)
        {
            //创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if(_sockfd == -1)
            {
                cout << "socket failed !!!!" << endl;
                exit(1);
            }
            cout << "socket sucess :" << _sockfd << endl;
        }


        void client_start()
        {
            string buffer;
            sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            peer.sin_family = AF_INET;
            peer.sin_addr.s_addr = inet_addr(_ip.c_str());
            peer.sin_port = htons(_port);
            while(_quit)
            {
                cout << "client#: ";
                cin >> buffer;
                int n = sendto(_sockfd, buffer.c_str(), buffer.size(), 0, (sockaddr*)&peer, sizeof(peer));
                if(-1 == n)
                {
                    cout << "sendto fail !!!\n"; 
                }
            }
        }

        ~udpClient()
        {}
    private:
        string _ip;
        uint16_t _port;
        int _sockfd;
        bool _quit = true;
    };



}

udpClient.cc

#include"udpClient.hpp"
#include<memory>


int main(int args, char* argv[])
{
    if(args != 3)
    {
        cout << "\nUsage:\n\t" << argv[0] << " _ip   _port\n\n";
    }
    unique_ptr<szg::udpClient> client(new szg::udpClient(argv[1], (uint16_t)atoi(argv[2])));
    client->client_start();
    return 0;
}

http://www.kler.cn/a/15651.html

相关文章:

  • C++创建型设计模式体现出的面向对象设计原则
  • Vue学习记录03
  • c# Encoding.GetEncoding
  • 高级计算机算法的8道题(贪心、动态规划)
  • 《Java核心技术 卷I》用户界面AWT事件继承层次
  • MySQL缓存使用率超过80%的解决方法
  • 【SpringBoot系列】实现跨域的几种方式
  • 院内导航方案怎么样?什么地图可以用于医院导航系统?
  • effective c++ item35-39
  • Apache Druid中Kafka配置远程代码执行漏洞(MPS-2023-6623)
  • 工厂能耗管理系统linux嵌入式边缘网关
  • 元宇宙展厅--音乐科技展厅
  • js字符串 常用方法 并带详细讲解
  • Java项目上线之云服务器环境篇(四)——Redis的安装与配置
  • 安卓开发_广播机制_发送自定义广播
  • RK3399平台开发系列讲解(LED子系统篇)LED子系统详解
  • Apache Zeppelin系列教程第一篇——安装和使用
  • springboot+nodejs+vue众筹项目管理系统平台系统
  • VUE入门神器
  • jvm调优策略
  • 牛客网Python入门103题练习|【07--循环语句(1)】
  • C语言入门篇——指针篇
  • ddp pytoch多卡分布式训练
  • Vue3之setup参数介绍
  • Java学习过程(韩顺平661-665)
  • 浅谈测试用例设计 | 京东云技术团队