首页 > 系统相关 >Linux——网络通信

Linux——网络通信

时间:2024-03-19 23:36:10浏览次数:27  
标签:网络通信 sockaddr addr int socket Linux include struct

一. 引入

Linux进程间通信包括多种机制,如管道、消息队列、信号、共享内存和信号量。这些机制都依赖于Linux内核提供的支持,用于实现不同进程之间的数据交换和同步。然而,这些通信方式在本地进程间通信中非常有用,但无法直接用于跨机器间的通信

二. 网络通信

在网络通信中,通信的基本要素包括地址数据,其中:

地址IP地址用于标识设备的位置,端口号用于标识设备上运行的具体服务。

数据:通信数据需要遵循特定的协议,如HTTP、TCP、UDP等。不同协议有不同的特点和用途,适用于不同类型的通信需求。

        

Socket网络编程:Socket是实现网络通信的接口,允许进程通过网络与其他进程进行通信。在Socket编程中,常用的协议有TCP和UDP,分别适用于可靠连接和无连接通信。

三. 字节序 

当数据在不同平台之间传输或交换时,需要考虑字节序的问题,以确保数据能够正确解释和处理。

1. litte-endian(x86系列CPU都是litte-endian的字节序):

        将低序字节存储在起始位置

2. Big-endian(网络字节序=Big-endian):

        将高序字节存储在起始位置

 

3. 例子:在内存中 0x01020304 的存储方式
       
    内存地址   4000&4001&4002&4003
        LE           04       03      02      01
        BE           01       02      03      04

4.编程实现判断大小字节序

#include <stdio.h>

union Data{
	char buf[4];
	int num;
};

int main(){
	union Data d1;
	d1.num = 0x11223344;
	printf("0x%x\n",d1.num);
	printf("0x%x%x%x%x\n",d1.buf[0],d1.buf[1],d1.buf[2],d1.buf[3]);
	return 0;
}

运行结果:

0x11223344
0x44332211

四. 网络编程API

1、socket()函数 

        用于创建网络套接字

#include<sys/types>
#include<sys/socket.h>
int socket(int domain, int type, int protocol); //网络类型
                                                //数据协议
                                                //一般为0,让系统配置适合前面俩个参数的协议

        返回值:成功返回一个socket文件描述符,失败返回-1

2、 bind()函数

        将给定的网络地址及端口号绑定到指定的socket套接字上。(注意:当我们调用函数把IP地址和端口号绑定到网络套接字之前,需要进行转化,如大小序转化)

#include<sys/types>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
//addrlen: sizeof(struct sockaddr)的大小

 my_addr: 一个指向strcut sockaddr的指针,根据socket不同的协议类型,其结构也不同。

 我们一般使用另一个结构体sockaddr_in这个结构体

  cd /usr/include/                grep "struct sockaddr_in {" * -nir                  vi linux/in.h +184 :

#include <linux/in.h> //这俩个头文件存在一个即可 #include <netinet/in.h>

/* IPv4*/
struct sockaddr_in
{
 uint16 sin_family;          /* 网络类型,如IPV4区域网*/
 uint16 sin_port;            /* 端口号 */
 uint32 sin_addr.s_addr;     /* ID地址 */
 unsigned char sin_zero[8];  /* 结构体占用内存大小 */
};

 //注意:当我们调用函数把IP地址和端口号绑定到网络套接字之前,需要进行转化,如大小序转化

/* Ditto, for IPv6.  */
struct sockaddr_in6
{
 uint16 sin6_family;         /* 网络类型*/
 uint16 sin6_port;           /* Transport layer port # */
 uint32 sin6_flowinfo;       /* IPv6 flow information */
 uint8  sin6_addr[16];       /* IPv6 address */
 uint32 sin6_scope_id;       /* IPv6 scope-id */
};

        返回值:成功返回0,失败返回-1

3、listen()函数

        将socket套接字变为监听套接字,准备接受客户端的连接。

#include<sys/types>
#include<sys/socket.h>
int listen(int socket,int num);
//num:内核监听队列的最大长度。

       返回值:执行成功返回0,失败返回-1

4. connect()函数


        客户端主动发送连接请求给服务器。

#include<sys/types>
#include<sys/socket.h>
int connect(int socket,struct sockaddr* addr,sockelen_t len );

       返回值:执行成功返回0,失败返回-1

5、accept()函数


        服务器阻塞等待客户端的连接。

#include<sys/types>
#include<sys/socket.h>
int accept(int socket,struct sockaddr* addr,sockelen_t* len );

         返回值:执行成功则返回一个新的socket套接字,我们可以利用这个套接字进行接下来的操作,使得旧的套接字继续执行别的客户端操作。

例子:

服务端Socket.c
#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(){
//1.创建socket网络套接字
    //int socket(int domain, int type, int protocol);
    int s_fd = socket(AF_INET,SOCK_STREAM,0); //配置网络类型为为因特尔网
                                              //配置数据传输的协议为TCP协议
                                              //一般写0,根据前俩个配置的参数自动去选择合适的协议                                    
    if(s_fd == -1){
        perror("socket"); 
        exit(-1);
    }

//2.绑定本地IP地址和端口号到socket网络套接字上
    // int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
    //我们一般不用第二个结构体,用的是下面这个结构体
    // struct sockaddr_in{
    //      uint16 sin_family;          /*网络类型*/
    //      uint16 sin_port;            /* Port number.  */
    //      uint32 sin_addr.s_addr;     /* Internet address.  */
    //      unsigned char sin_zero[8];  /* Pad to size of `struct sockaddr'.  */
    // };
    struct sockaddr_in s_addr;
    memset(&s_addr,0,sizeof(struct sockaddr_in));
   
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(8989); //端口号
    inet_aton("192.168.190.130",&s_addr.sin_addr);
    bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));

//3.将socket套接字变为监听套接字,准备接受客户端的连接
    //int listen(int socket,int num);
    listen(s_fd,10); //最多接受10个用户的连接

//4.服务器阻塞等待客户端的连接。
    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); addr客户端的信息
    struct sockaddr_in c_addr;
    memset(&c_addr,0,sizeof(struct sockaddr_in));
    socklen_t len = sizeof(struct sockaddr_in);
    int c_fd = accept(s_fd,(struct sockaddr*)&c_addr,&len);
    if(c_fd == -1){
        perror("accept"); //输出表示最近一次 socket() 系统调用的错误信息
        exit(-1);
    }
    printf("Success Connected\n");
    //打印客户端的IP地址
    printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));

//5.读取客户端发送过来的消息
    char readBuf[128];
    int n_read = read(c_fd,readBuf,128);
    if(n_read == -1){
        perror("read");
    }else{
        printf("get message:%d,%s\n",n_read,readBuf);
    }

//6.向客户端发送一条消息
    write(c_fd,"I get your message",sizeof("I get your message"));

    return 0;
}
客户端User.c
#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(){
//1.创建socket网络套接字
    //int socket(int domain, int type, int protocol);
    int c_fd = socket(AF_INET,SOCK_STREAM,0); //配置网络类型为为因特尔网
                                              //配置数据传输的协议为TCP协议
                                              //一般写0,根据前俩个配置的参数自动去选择合适的协议                                    
    if(c_fd == -1){
        perror("socket"); 
        exit(-1);
    }

//2.连接服务端
    //int connect(int socket,struct sockaddr* addr,sockelen_t len ); addr包含服务端的地址信息
    struct sockaddr_in s_addr;
    memset(&s_addr,0,sizeof(struct sockaddr_in));
    s_addr.sin_family = AF_INET; //注意,这句话至关重要
    inet_aton("192.168.190.130",&s_addr.sin_addr); //IP地址
    s_addr.sin_port = htons(8989); //端口号
    if(connect(c_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in)) == -1){
        perror("connect");
        exit(-1);
    }
    //打印服务端的IP地址
    printf("get connect from Socket:%s\n",inet_ntoa(s_addr.sin_addr));

//3.发送信息到服务端
    char *msg="msg from client";
    write(c_fd,msg,strlen(msg));

//4.读取服务端发来的消息
    char readBuf[128];
    int n_read = read(c_fd,readBuf,128);
    if(n_read == -1){
        perror("read");
    }else{
        printf("get message from Socket :%d,%s\n",n_read,readBuf);
    }

    return 0;
}

运行结果:

标签:网络通信,sockaddr,addr,int,socket,Linux,include,struct
From: https://blog.csdn.net/m0_73510889/article/details/136836986

相关文章

  • Linux进程通信——信号
    一.信号的名字和编号1.每个信号都有一个编号和名称,这些名字都以“SIG”开头。  (kill-l命令可显示出当前系统支持的信号的编号和名称)二.信号的处理1.信号的处理有三种方法:  忽略,捕捉,默认动作忽略:有俩种信号不可被忽略(SIGKILL和SIGSTOP),其向 内核 和 超......
  • Linux脏牛提权漏洞复现(DirtyCow)
    #简述脏牛(DirtyCow)是Linux中的一个提权漏洞。主要产生的原因是Linux系统的内核中Copy-on-Write(COW)机制产生的竞争条件问题导致,攻击者可以破坏私有只读内存映射,并提升为本地管理员权限。#前期准备靶机:vulnhub——Lampiao192.168.230.217攻击机:Kali192.168.230.128#复现......
  • 【Linux】 生产消费者模型
    线程同步同步: 在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,这就叫做同步(饥饿问题:某些线程无法得到资源而长时间无法执行,常见的就是申请不到锁)竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。单纯的加锁会引起问题。如......
  • [Linux]文件缓冲区
    文件fd输出重定向除了用dup2()改变数组下标外,还可以用命令来完成所有的命令执行,都必须有操作系统将其运行起来变成进程,然后根据>>,<<来判断是输入重定向,还是输出重定向。缓冲区之所以有缓冲区,是为了提高效率的。就类比快递一样,如果你送一个东西给北京的朋友,那么你自己......
  • 操作系统实践之路——五、初始化(2.Linux初始化)
    文章目录一、全局流程二、从BIOS到GRUB三、GRUB是如何启动的四、详解vmlinuz文件结构五、流程梳理-1六、内核初始化从_start开始七、流程梳理-2参考资料前言​本章节将讨论一下Linux如何去做初始化。一、全局流程​在机器加电后,BIOS会进行自检,然后由BIOS加载......
  • 从 Linux 内核角度探秘 JDK MappedByteBuffer
    本文涉及到的内核源码版本为:5.4,JVM源码为:OpenJDK17,RocketMQ源码版本为:5.1.1在之前的文章《一步一图带你深入剖析JDKNIOByteBuffer在不同字节序下的设计与实现》中,笔者为大家详细剖析了JDKBuffer的整个设计体系,从总体上来讲,JDKNIO为每一种Java基本类型定义了对......
  • Linux TCP/UDP CS模型
    LinuxTCP/UDPCS模型目录LinuxTCP/UDPCS模型TCPServer/TCPClientUDPServer/UDPClientTCPServer/TCPClient在C语言中实现一个TCP服务器时,使用select函数可以帮助我们同时监控多个文件描述符(包括socket)的状态,从而实现非阻塞的I/O操作。以下是一个简单的TCP服务器示例,它......
  • linux命令 --简化版--快速上手
    linux命令--简化版--快速上手系统信息arch显示机器的处理器架构(1)uname-m显示机器的处理器架构(2)uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMB[IOS](https://www.2cto.com/kf/yidong/iphone/)/DMI)hdparm-i/dev/hda罗列一个磁盘的......
  • linux--shell 一般把脚本文件放到哪里
    linux--shell一般把脚本文件放到哪里shell在Linux系统中,脚本文件的存放位置取决于其用途和类型。以下是几个常见的脚本存放位置:系统级脚本:这些脚本通常与系统管理、初始化、配置或权限认证相关。/usr/bin:主要存放所有用户都可用的系统程序,即普通的基本命令。/etc:存放系统......
  • linux下永久添加静态路由-不同
    linux下永久添加静态路由-不同添加路由的命令:1,routeaddrouteadd-net192.56.76.0netmask255.255.255.0deveth0#添加一条静态路由routeadddefaultgw192.168.0.1#添加默认路由routedel-net192.168.1.0/24gw192.168.0.1#删除一条路由route-n#查看路由表2,ipr......