socket(网络通信)从入门到精通(1)

Socket并不是一种网络协议,而是操作系统提供的一套网络通信接口。应用程序通过Socket接口调用操作系统中的TCP/IP协议栈,即可实现不同计算机之间的数据传输。因此,学习Socket网络编程,就是学习如何让程序具备网络通信能力。要学习socket,必须了解必备网络常识:

   一、基础知识

(1)网络模型

          OSI七层模型(Open System Interconnection)

         7

       七层模型是理想中的模型,OSI七层模型是国际标准化组织(ISO)提出的一种网络参考模型,其主要目的是帮助人们理解网络通信的原理以及各层之间的职责划分,

        实际开发中常用大多数操作系统(如Linux、Windows、Android等)并没有严格按照OSI七层模型实现网络协议,而是采用了更加简洁、高效的TCP/IP四层协议模型。

        4

    (2)IP  网关 子网掩码  端口

             IP:     IP地址是网络层(Internet Protocol,IP协议)用于标识网络设备的一组数字地址。只要设备接入网络,就需要拥有一个IP地址。

     目前最广泛使用的是IPv4地址。IPv4地址长度为32位(二进制),通常被划分为4个字节,每个字节占8位,并使用点号进行分隔,因此又称为点分十进制表示法。

    ex:192.168.32.xxx

            网关 :     划分网络部分和主机部分,这组数据就是子网掩码(Subnet Mask),也即是路由器。

    192.168.32.xxx,这个IP中,32表示一个域,这个域中的网关是,192.168.32.255 

    192.168.33.xxx,同理,33是一个域,网关是192.168.33.255 

    网络通信中,IP与IP间通信需要网关。

   ex:32.xxx与32.xxx通信  32.ip->32.网关->32.ip

   ex:32.xxx与33.xxx通信  32.ip->32.网关->33.网关->33.IP

         子网掩码: 网关怎么判断是不是一个域?通过 子网掩码(255.255.255.0) 子网掩码对IP进行&,

    ex:192.168.32.111 & 255.255.255.0  =192.168.32.0

    ex:192.168.33.121 & 255.255.255.0  =192.168.33.0

         

         Port端口

     IP地址能够唯一标识网络中的一台计算机。当客户端发送数据时,首先会根据目标IP地址将数据传输到指定的计算机。但是在实际开发过程中,一台计算机通常会同时运行多个网络应用程序,例如Web服务器、SSH远程登录服务、MySQL数据库等。当数据到达目标计算机后,仅依靠IP地址已经无法确定数据应该交由哪一个应用程序进行处理。

      因此,TCP/IP协议在传输层引入了端口号(Port)的概念。端口号用于标识计算机中的网络应用程序,使操作系统能够将收到的数据准确地交付给对应的程序进行处理。可以理解为IP地址负责找到目标计算机,而端口号负责找到目标计算机中的目标程序。

     端口号是传输层(TCP/UDP)中用于标识应用程序的一组数字,可以理解为网络程序在操作系统中的"编号"。

     为了能够区分大量不同的网络应用程序,TCP和UDP协议都采用16位无符号整数表示端口号,因此端口号的取值范围为0~65535

 

二、socket编程的原理与应用

  • 基本概念

TCP/IP协议栈属于操作系统内核的一部分,普通应用程序无法直接操作这些底层协议,更不能直接控制网卡完成数据发送和接收。为了解决这一问题,操作系统提供了Socket接口。应用程序只需要调用Socket提供的一系列函数,即可完成网络连接、数据发送、数据接收以及连接关闭等操作,而底层的数据封装、路由选择、差错控制等工作则由TCP/IP协议栈自动完成。

  • 地址结构

Socket通信需要IP地址、端口号以及传输协议三个基本要素。在编写Socket程序时,这些信息不能单独传递,而是需要按照规定的格式组织在一起,然后作为参数传递给相关函数。

      为了统一描述网络通信双方的地址信息,Linux系统定义了一组专门的数据结构,用于保存IP地址、端口号以及协议族等信息。

ex:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

//巴法云的端口
#define BEMFA_TCP_PORT  8344

#define BEMFA_IP_ADDR   "119.91.109.180"

#define BEMFA_UID       "95783ff664654238b71c6a12b0db1bef"

#define TOPIC           "led002"

int main()
{
    //1.创建TCP套接字
    int sock_fd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sock_fd)
    {
        fprintf(stderr,"create socket error:%s\n",strerror(errno));
        exit(1);
    }

    //2.构造目标主机信息
    struct sockaddr_in dest_addr;
    memset(&dest_addr,0,sizeof(dest_addr));

    dest_addr.sin_family = AF_INET;     //协议族
    dest_addr.sin_port   = htons(BEMFA_TCP_PORT);   //端口号  需要转换为网络字节序
    dest_addr.sin_addr.s_addr = inet_addr(BEMFA_IP_ADDR); //IP地址 需要转换为网络字节序  


    //3.连接目标主机
    int ret = connect(sock_fd,(struct sockaddr *)&dest_addr,sizeof(dest_addr));
    if(-1 == ret)
    {
        fprintf(stderr,"connect bemfa.com error:%s\n",strerror(errno));
        close(sock_fd);
        exit(1);
    }
    printf("=======连接巴法云服务器成功=======\n");

    //4.订阅主题
    char recvbuf[256] = {0};
    char sendbuf[256] = {0};
    sprintf(sendbuf,"cmd=1&uid=%s&topic=%s\r\n",BEMFA_UID,TOPIC);
    send(sock_fd,sendbuf,strlen(sendbuf),0);
    recv(sock_fd,recvbuf,256,0);
    printf("recv data from bemfa = %s\n",recvbuf);

    while(1)
    {  
         //5.发布消息
        char buf[256] = {0};
        sprintf(buf,"cmd=2&uid=%s&topic=%s&msg=on\r\n",BEMFA_UID,TOPIC);
         send(sock_fd,buf,strlen(buf),0);
       
         sleep(5);

         sprintf(buf,"cmd=2&uid=%s&topic=%s&msg=off\r\n",BEMFA_UID,TOPIC);
         send(sock_fd,buf,strlen(buf),0);

        sleep(5);

        recv(sock_fd,buf,256,0);
        printf("recv data from bemfa = %s\n",buf);
    }
}

 

posted on 2026-07-27 19:04  撒与日  阅读(8)  评论(0)    收藏  举报