IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux系统编程之网络编程(SOCKET) -> 正文阅读

[系统运维]linux系统编程之网络编程(SOCKET)


Socket可以看成是用户进程与内核网络协议栈的接口可以把socket看作进程间通信的一种方式,它是全双工的通信方式, 其不仅可以用于本机进程间通信,可以用于网络上不同主机的进程间通信, 甚至还可以用于异构系统之间的通信。

字节序

1.大端字节序(Big Endian)

最高有效位存储于最低内存地址处,最低有效位存储于最高内存地址处。

2.小端字节序(Little Endian)

最高有效位存储于最高内存地址处,最低有效位存储于最低内存地址处。

3.主机字节序

不同的主机有不同的字节序,如x86为小端字节序。

4.网络字节序

网络字节序规定为大端字节序

在编程时,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);
       int inet_aton(const char *cp, struct in_addr *inp);
       char *inet_ntoa(struct in_addr in);


要给端口号赋值时可以用这几个函数
htonl(将32位主机字符顺序转换成网络字符顺序)

返回值:返回对应的32位网络字符顺序。

htons(将16位主机字符顺序转换成网络字符顺序)

返回值:返回对应的16位网络字符顺序。

ntohl (将32位网络字符顺序转换成主机字符顺序)

返回值:返回对应的32位主机字符顺序

ntohs (将16位网络字符顺序转换成主机字符顺序)

返回值:返回对应的16位主机字符顺序

要给IP地址赋值时可以用这几个函数
inet_aton (将主机序列转换为网络字节序列)

cp是格式为主机号序列的ip地址
inp是存放网络字节序列的结构体

inet_ntoa(将网络字节序列转换成主机字节序列)

in是存放网络字节序列的结构体
返回值:主机序列的IP地址

API

服务端
 #include <sys/types.h>         
 #include <sys/socket.h>
	struct sockaddr_in {
  __kernel_sa_family_t  sin_family;      
  __be16                sin_port;      
  struct in_addr        sin_addr;      

  };

	struct sockaddr {
  sa_family_t sa_family;
  char        sa_data[14];
  }
	struct in_addr {
  __be32  s_addr;
  };

    int socket(int domain, int type, int protocol);
	int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	int listen(int sockfd, int backlog);
	int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	//int accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags);
	

socket

socket是为了获得套接字的函数

domain:指定通信协议族,一般取值AF_INET,ipv4协议族
type :指定socket类型, 流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW,因为用的是tcp/ip协议,这里一般会使用流式套接字
protocol:为协议类型,一般取0,会默认选择

bind

bind是和套接字绑定端口号绑定ip地址和端口号

sockfd:是服务端套接字
addr:存放IP地址和端口号的结构体,这里会使用sockaddr_in,也就是ipv4套接字地址结构,所以在传递参数时需要进行强制转换,想单独寻找sockaddr_in的原型的话,可以在/usr/include下使用如下指令

grep "sockaddr_in{" * -nir  n显示行号,i不区分大小写,r递归查找

addrlen:传入的结构体的大小

listen

listen监听客户端的接入

sockfd:是服务端套接字
backlog:是已经发出信号给服务端,并等待完成三次握手的过程中的客户端和已经完成连接的客户端,这两个队列之和的最大值

accept

accept接受到服务端的连接

sockfd:服务器套接字
addr:客户的套接字地址, 不关心的话, 可以设置为NULL
addrlen:客户的套接字地址长度, 不关心的话可以设置成为NULL, 否则一定要初始化
返回值为客户端的套接字,如果没有连接上客户端将会一直阻塞,accept4多了一个flag参数,当该参数设置为0时,效果是和accept一样,但是可以设置为 SOCK_NONBLOCK,也就是非阻塞的形式,所以zuihao还是选用accept,因为服务端的建立就是为了收到客户端的请求的

客户端
 #include <sys/types.h>         
 #include <sys/socket.h>
 int socket(int domain, int type, int protocol);
 int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

 
socket:获得客户端的套接字,格式和服务端一样。

connect

connect:尝试获得与服务器的连接

sockfd:服务端的套接字
addr:存放IP地址和端口号的结构体指针,这里的是目标服务器的IP地址和端口号
addrlen:传入结构体的大小

当服务器和客户端建立的连接后,给对方发送数据就可以用read和write函数发送了

这里综合以上函数写的例子,效果是客户端和服务端可以互相收发消息

服务端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(int argc,char **argv){

        int s_fd;
        int c_fd;
        int size;
        int pid;
        struct sockaddr_in s_addr;
        struct sockaddr_in c_addr;
        char readbuf[128]={0};
        char writebuf[128]={0};
        memset(&s_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));
        size=sizeof(c_addr);


        s_fd=socket(AF_INET,SOCK_STREAM,0);
        if(s_fd==-1){
                perror("socket");
                exit(-1);
        }
        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);

        if(bind(s_fd,(struct sockaddr *)&s_addr,sizeof(s_addr))){

                perror("bind");
                exit(-1);
        }
        listen(s_fd,10);
        while(1){
                c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&size);
                if(c_fd==-1){
                        perror("accept");
                        exit(-1);
                }
 pid=fork();
                if(pid==0){
                        while(1){
                                memset(writebuf,0,strlen(writebuf));
                                printf("请输入消息:\n");
                                gets(writebuf);
                                write(c_fd,writebuf,strlen(writebuf));
                                printf("服务端子:%d\n",getpid());

                        }
                }
                else if(pid>0){
                        while(1)
                        {
                                printf("客户端的ip地址是:%s\n",inet_ntoa(c_addr.sin_addr));

                                read(c_fd,readbuf,sizeof(readbuf));
                                printf("接受的消息是:%s\n",readbuf);
                                memset(readbuf,0,sizeof(readbuf));
                                printf("服务端父:%d\n",getpid());

                        }
                }
        }
        return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(int argc,char **argv){

        int c_fd;
        int size;
        struct sockaddr_in c_addr;
        char readbuf[128];
        char writebuf[128];
        int pid;
        memset(&c_addr,0,sizeof(struct sockaddr_in));


        c_fd=socket(AF_INET,SOCK_STREAM,0);
        if(c_fd==-1){
                perror("socket");
                exit(-1);
        }
        c_addr.sin_family=AF_INET;
        c_addr.sin_port=htons(atoi(argv[2]));
        inet_aton(argv[1],&c_addr.sin_addr);

        if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(c_addr))==-1){
                perror("connect");
                exit(-1);
        }

        pid=fork();
        if(pid==0){
                while(1){
                        sleep(1);
                        read(c_fd,readbuf,sizeof(readbuf));
                        printf("收到的消息是:%s\n",readbuf);
                        printf("客户端子:%d\n",getpid());
                        memset(readbuf,0,sizeof(readbuf));
                }

        }
         else if(pid>0){
                while(1){
                        memset(writebuf,0,sizeof(writebuf));
                        printf("请输入消息:\n");
                        gets(writebuf);
                        write(c_fd,writebuf,strlen(writebuf));
                        printf("客户端父:%d\n",getpid());
                }
        }




        return 0;
}


在这里插入图片描述

在写客户端之前如果要先测试服务端是否能正常运行,可以用windows自带的telnet来测试

在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:38:53  更:2021-07-27 16:40:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 18:03:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码