Linux——网络通信

目录

一. 引入

二. 网络通信

三. 字节序 

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.编程实现判断大小字节序

四. 网络编程API

1、socket()函数 

2、 bind()函数

3、listen()函数

4. connect()函数

5、accept()函数

例子:

服务端Socket.c

客户端User.c

运行结果:

例子2:

服务端Socket2.c

客户端User2.c


一. 引入

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

二. 网络通信

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

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

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

        

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

三. 字节序 

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

1. litte-endianx86系列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;
}

运行结果:

例子2:

        以下程序可实现双方聊天

服务端Socket2.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(){
    char msg[128] = {0};
//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;
    while(1){
        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));

        if(fork() == 0){
            while(1){
                memset(msg,0,sizeof(msg));
                printf("Input: \n");
                fgets(msg, sizeof(msg), stdin);
                write(c_fd,msg,strlen(msg));
            }
        }

        char readBuf[128];
        int n_read;
        while(1){
            n_read = read(c_fd, readBuf, 128);
            if(n_read == 0){
                printf("Client disconnected\n");
                break;  // 终止循环,跳出读取消息
            } else if(n_read == -1){
                perror("read");
            } else {
                printf("get message: %d, %s\n", n_read, readBuf);
                memset(readBuf, 0, sizeof(readBuf)); // 清空读取缓冲区
            }
        }
    }
    return 0;
}
客户端User2.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(){
    char msg[128] = {0};
//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);
    }
    int fd = fork();
    if(fd == 0){
        while(1){
            memset(msg,0,sizeof(msg));
            printf("Input: \n");
            fgets(msg, sizeof(msg), stdin);
            write(c_fd,msg,strlen(msg));
        }
    }
    while(1){
        char readBuf[128];
        int n_read;
        n_read = read(c_fd, readBuf, 128);
        if(n_read == 0){
            printf("Client disconnected\n");
            break;  // 终止循环,跳出读取消息
        } else if(n_read == -1){
            perror("read");
        } else {
            printf("get message form Socket: %d, %s\n", n_read, readBuf);
            memset(readBuf, 0, sizeof(readBuf)); // 清空读取缓冲区
        }
    }
    return 0;
}

  • 33
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@尘音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值