您现在的位置是:首页 >技术交流 >socket套接字通信 TCP传输控制协议/IP网络协议 5.18网站首页技术交流

socket套接字通信 TCP传输控制协议/IP网络协议 5.18

孤独memories 2024-06-17 10:47:47
简介socket套接字通信 TCP传输控制协议/IP网络协议 5.18

B/S :浏览器和服务器

C/S :客户机和服务器

网络的体系结构:

网络的层次结构和每层所使用协议的集合

网络采用分层管理的方法,将网络的功能划分为不同的模块

OSI模型:

共7种:

			应用层:接收用户的数据,面向的应用程序

​			表示层:逻辑语言转为机器语言,翻译,加密

​			会话层:针对传输的每一种数据建立一条虚连接
高层

​			传输层:作用 1.区分流量   2.定义数据传输方式

​			网络层:network  编址  寻址

​			数据链路层:数据链路层分为LLC层(逻辑链路控制子层)和MAC层(介质访问控制子层)
						二层地址:MAC地址(介质访问控制)-							-物理/硬件/烧录地址

​			物理层:传输介质(有线、无线)
地层

TCP/IP协议:传输控制协议 / 网络协议

用户模式
应用层:使用相应的协议,将封装好的数据提交给传输层,或是传输层接收数据并处理。 FTP头信息
内核模式:
传输层:负责实现应用程序之间的通信服务,又称端对端通信 TCP头信息
网络层:负责主机间的通信,传输数据包 IP头信息
网络接口层:将二进制转化为数据帧,并进行数据帧的发送和接受

数据的封装与传递过程:

在这里插入图片描述

网络传输数据大小user data: 6~1460

网络传输中容易发生拆包和粘包,所以接收和发送的字节数要对齐,否则容易传输不上

TCP和UDP协议

共同点:传输层,全双工的

不同点:TCP有连接可靠的,UDP无连接不可靠数据容易丢

TCP

是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)

传输质量较高,输出大量数据

传输需要账号,一对一

传输数据时较慢

UDP

(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

发送小尺寸数据,无线网络

广播/组播式通信中,一对多

实时性较高

传输数据时快,资源消耗小

网络编程

1.预备知识

1)socket套接字

网络编程的通用接口

是一种特殊的文件描述符

当调用socket函数时就会创建一个套接字,并返回套接字的文件描述符

支持面向连接(TCP)与无连接(UDP)

套接字的类型

TCP所用的时流式套接字,用于可靠传输,SOCK_STREAM

UDP所用的数据报套接字,用于无连接不可靠的,SOCK_DGRAM

SOCK_RAW:原始套接字,直接作用于网络层

套接字位于应用层与传输层之间,OSI模型的会话层和传输层之间

2)IP地址

IP地址就是网络中主机的标识—区分不同的主机

IP地址:IPv4(32)和IPv6(128)

IP地址表示:点分形式;例:192.168.2.99

IP地址 = 网络号 + 主机号

​ 网络号:IP & 子网掩码

​ 主机号:IP & (-子网掩码)

同一局域网内主机号,网络号相同,主机号不同

Linux:

​ ifconfig : 查看IP地址

​ ifconfig ens33 up/down/IP … 启动/关闭/设置IP

​ ping IP/域名 : 检测网络是否联通

6、解决有线无无法边接:显示Wired Unmanaged
		{
			dashhome/system setting/network。显示Wired Unmanaged

​			解决方法:
​			sudo vim /etc/NetworkManager/NetworkManager.conf
​			将managed=false
​			改成managed=true
​			然后重启network-manager
​			sudo service network-manager restart
​			或者 kill掉再启用:sudo NetworkManager。再不行就重启:sudo reboot
​		}

IP地址的转换

inet_aton()

字符串->网络字节序

将strptr所指的字符串转换成32位的网络字节序二进制值
    #include <arpa/inet.h>
    int inet_aton(const char *strptr,struct in_addr *addrptr);

inet_addr()

字符串->网络字节序并且返回地址

功能同上,返回转换后的地址。
    in_addr_t inet_addr(const char *strptr);

inet_ntoa()

网络字节序->字符串

32位网络字节序二进制地址转换成点分十进制的字符串。 
    char *inet_ntoa(stuct in_addr inaddr);

3)端口号

同一台主机上区分不同任务的标识

一台主机接收到的数据包应该转交给哪个任务来处理

类型:unsigned short (1~65536)

保留端口 1~1023
系统分配端口 1024~5000
自己分配端口 5001~65536

4)字节序(大小端)

小端存储:低字节数据存在低地址,高字节数据存储在高地址

​ 先存fd

大端存储:低字节数据存在高地址,高字节数据存储在低地址

​ 先存fa

unsigned int a = 0xfafbfcfd
    fa高字节数据
    fd低字节数据
    
    /*===============================================
*   文件名称:zijiexu.c
*   创 建 者:memories 
*   创建日期:2023年05月18日
*   描    述:
================================================*/
    
 地址由低到高存储,如果存的是fd则是小段存储
    
#include <stdio.h>

int main(int argc, char *argv[])
{ 
    unsigned int a = 0xfafbfcfd;
    unsigned char *p = (unsigned char*)&a;
    printf("*p=%x
",*p);//%x表示十六进制

    return 0;
} 

hqyj@ubuntu:~/5.18$ gcc zijiexu.c
hqyj@ubuntu:~/5.18$ ./a.out 
*p=fd
 

网络传输统统使用大端序,所以大端序也称为网络字节序

主机一般使用小端序,所以小端序也称为主机字节序

网络字节序和主机字节序的转换

主机字节序到网络字节序
u_long htonl (u_long hostlong);
u_short htons (u_short short);

网络字节序到主机字节序
u_long ntohl (u_long hostlong);
u_short ntohs (u_short short);

2.TCP网络编程框架

类似于app是客户端,app中的内容是服务器提供的

***服务器(server)流程***					

socket ---- 创建套接字,两者都要创建
bind   ---- 绑定本机地址和端口
listen ---- 设定监听套接字,检测是否有客户端访问服务器
accept ---- 接收客户端的连接,并生成通信套接字

read/write() ---- 接收/发送数据
close()       ---- 关闭套接字

-----------------------------------------------------

***客户端:client***

socket ---- 创建套接字,两者都要创建
connect ---- 主动连接服务器


write/read() ---- 发送/接收数据
close()      ---- 关闭套接字







3.网络编程接口

1)socket()

作用:创建套接字
函数:
	#include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
int socket(int domain, int type, int protocol);

参数:
	domain:地址族:AF_INET:IPv4 internel protocol
	type:套接字类型
			SOCK_STREAM:流式套接字 TCP
			SOCK_DGRAM:数据报套接字 UDP
	protocol:0
返回值:
	成功:套接字文件描述符
	失败:-1,并设置error

2)bind()

作用:绑定本机地址和端口
函数:
		#include <sys/types.h>          
       #include <sys/socket.h>
    
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:
    sockfd:套接字文件描述符
    addr:地址结构体
    addrlen:地址长度
返回值:
	成功:0
	失败:-1,并设置error
    
地址结构:
    struct sockaddr {  //通用地址
               sa_family_t sa_family;
               char        sa_data[14];
           }

    struct sockaddr_in { //IPv4地址结构
               sa_family_t    sin_family; /* address family: AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };

          	 /* Internet address. */
      struct in_addr { //网络字节序
               uint32_t       s_addr;     /* address in network byte order */
           };


例如:
    //用IPv4结构体
    struct sockaddr_in srvaddr;
	memset(&srvaddr,0,sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;//指定地址族为IPv4的地址
	srvaddr.sin_port = htons(6666);//端口号
	srvaddr.sin_addr.s_addr = inet_addr("192.168.2.84");//将点分式的字符串转化32位的网络字节序

	bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr));

3)listen

作用:设置监听套接字
函数:
	#include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>

    int listen(int sockfd, int backlog);
参数:	
    sockfd:套接字描述符
    backlog:监听队列长度(>0)
返回值:
	成功:0
	失败:-1,并设置error

4)accept()

作用:接收客户端的连接,并生成通信套接字
函数:
    
		#include <sys/types.h>          /* See NOTES */       #include <sys/so
    
    cket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:
    sockfd:套接字文件描述符
    addr:客户端地址结构体
    addrlen:客户端地址长度
    当不需要知道连接的客户端是谁时,第23参数都可以设置NULL
返回值:
	成功:连接成功的通信套接字
	失败:-1,并设置error
服务器套接字:
监听套接字(普通套接字转为监听套接字):用于监听、连接
通信套接字:用于通信(发送、接收)
/*===============================================
*   文件名称:server.c
*   创 建 者:memories 
*   创建日期:2023年05月18日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>


int main(int argc, char *argv[])
{ 
    //1.创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        return -1;
    }
    printf("socket-----------------
");
    //2.绑定本机地址和端口
     //用IPv4结构体
    struct sockaddr_in srvaddr;
	memset(&srvaddr,0,sizeof(srvaddr));
	srvaddr.sin_family = AF_INET;//指定地址族为IPv4的地址
	srvaddr.sin_port = htons(5429);//端口号
	srvaddr.sin_addr.s_addr = inet_addr("192.168.2.84");//将点分式的字符串转化32位的网络字节序

	if(0 > bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr)))
    {
        perror("bind");
        return -1;
    }
    printf("bind-----------------
");
    //3.设置监听套接字
    if(0>listen(sockfd,5))//必须写大于1的整数
    {
        perror("listen");
        return -1;
    }
    printf("listen-----------------
");
    //4.接受客户端的连接,并生成通信套接字
    int connfd = accept(sockfd,NULL,NULL);
    if(connfd < 0)
    {
        perror("accept");
        return -1;
    }
    printf("accept-----------------
");
    //5.与客户端通信
    int ret;
    char buf[1024];
    while(1)
    {
        memset(buf,0,sizeof(buf));
        ret = read(connfd,buf,sizeof(buf));
        if(ret < 0)
        {
            perror("read");
            break;
        }
        else if(ret == 0)
        {
            printf("write close
");
            break;
        }
        printf("recv:%s
",buf);

        if(0 > write(connfd,buf,ret))
        {
            perror("write");
            return -1;
        }
    }
    //6.关闭套接字
    close(sockfd);
    close(connfd);
    return 0;
} 

/*===============================================
*   文件名称:client.c
*   创 建 者:memories 
*   创建日期:2023年05月18日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{ 
    //1.创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        return -1;
    }
    printf("sockfd:%d
",sockfd);
    printf("socket------------
");
    //2.主动连接服务器
    struct sockaddr_in sockst;
    sockst.sin_family = AF_INET;
    sockst.sin_port = htons(5429);
    sockst.sin_addr.s_addr = inet_addr("192.168.2.84");
    int conn = connect(sockfd,(struct sockaddr*)&sockst,sizeof(sockst));
    if(conn <0)
    {
        perror("connect");
        return -1;
    }
    while(1)
    {
       char buf[1024]={0};
       fgets(buf,sizeof(buf),stdin);
       write(sockfd,buf,strlen(buf));
       if(strncmp(buf,"quit",4)==0)
       {
           break;
       }
    }
    //3.关闭套接字通信
    close(sockfd);
    return 0;
} 

hqyj@ubuntu:~/5.18$ gcc client.c
hqyj@ubuntu:~/5.18$ ./a.out 
sockfd:3
socket------------
你好
? 

hqyj@ubuntu:~/5.18$ gcc server.c
hqyj@ubuntu:~/5.18$ ./a.out 
socket-----------------
bind-----------------
listen-----------------
accept-----------------
recv:你好

recv:?

    
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。