要变优秀的科啊啊啊啊啊啊!!!

要变优秀的科啊啊啊啊啊啊!!!

TCP是传输层的协议

TCP头部格式

TCP通信-LMLPHP

  1. 源/目的端口:表示数据从哪个进程发送,发送到哪个进程去
  2. 序号:发送端发送数据包的编号
  3. 确认号:已经确认接收到的数据的编号(只有当ACK为1时,确认号才有用)
  4. URG:紧急指针是否有效
    ACK:确认号是否有效
    PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
    RST:对方要求重新建立连接,把携带RST标识的称为复位报文段
    SYN:请求建立连接,把携带SYN标识的称为同步报文段
    FIN:通知对方,要关闭连接了,把携带FIN标识的称为结束报文

  5. 16位窗口大小:进行流量窗口控制
  6. 16位校验和:检验数据是否一致
  7. 16位紧急指针:标识哪部分数据是紧急数据

TCP为什么安全可靠:


1.在通信前建立三次握手连接
    SYN
    SYN+ACK 
    ACK 

2.在通信过程中通过序列号和确认号保障数据传输的完整性
    本次发送序列号:上次收到的确认号
    本次发送确认号:上次接收到的序列号 + 实际接收的数据长度

  在传输过程中使用滑动窗口实现流量控制

3.在通信结束时使用四次挥手结束连接保障数据传输的完整性

TCP通信-LMLPHP 

UDP和TCP的区别:
    1.UDP和TCP都是传输层的协议
    2.UDP实现机制简单、资源开销小、不安全不可靠
    3.TCP实现机制复杂、资源开销大、安全可靠
    4.UDP是无连接的、TCP有连接的、UDP是以数据包形式传输、TCP是以流的方式传输

TCP通信实现流程 

TCP通信-LMLPHP

 需要用到的接口

TCP发端:
  

1. socket():

创建一个套接字(socket descriptor),用于网络通信。通常使用如下代码:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);


其中,AF_INET 表示使用IPv4协议族,SOCK_STREAM 表示使用面向连接的TCP协议。
 

2. connect():

尝试与服务端建立连接。需要提供服务端的IP地址和端口号。例如:struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT)

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


  功能:
    发送链接请求
  参数:
    sockfd:套接字文件描述符
    addr:目的地址存放空间首地址
    addrlen:IP地址的大小
  返回值:
    成功返回0
    失败返回-1 

3.send ():

ssize_t send(int sockfd, const void *buf, size_t len, int flags);


  功能:
    发送数据
  参数:
    sockfd:文件描述符
    buf:发送数据空间首地址
    len:发送数据的长度
    flags:属性默认为0 
  返回值:
    成功返回实际发送字节数
    失败返回-1 
    recv 

4.recv():

ssize_t recv(int sockfd, void *buf, size_t len, int flags);


  功能:
    接收数据 
  参数:
    sockfd:套接字文件描述符 
    buf:存放数据空间首地址
    len:最大接收数据的长度
    flags:属性默认为0 
  返回值:
    成功返回实际接收字节数
    失败返回-1 
    如果对方退出,返回0 


  5.  close ():

close(sockfd);

销毁套接字文件描述符

int CreateTcpClient(char *pip, int port)
{
	int ret = 0;
	int sockfd = 0;
	struct sockaddr_in seraddr;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("fail to socket");
		return -1;
	}

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(port);
	seraddr.sin_addr.s_addr = inet_addr(pip);
	ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
	if (-1 == ret)
	{
		perror("fail to connect");
		return -1;
	}
	
	return sockfd;
}

 

struct sockaddr_in seraddr;

struct sockaddr_in seraddr;是C语言中声明一个 struct sockaddr_in 类型变量 seraddr的语句。


struct sockaddr_in是一个用于存储Internet(IPv4)协议地址信息的标准结构体,广泛应用于网络编程,特别是在使用TCP或UDP套接字时。


struct sockaddr_in结构体通常包含以下几个成员:

其中:
在实际使用中,struct sockaddr_in
 通常用于以下场景:
例如,创建一个表示服务器监听地址的 struct sockaddr_in变量:
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;  // IPv4地址家族
seraddr.sin_port = htons(SERVER_PORT);  // 将主机字节序端口号转换为网络字节序
seraddr.sin_addr.s_addr = inet_addr(pip);  // 将点分十进制IP地址字符串转换为网络字节序整数

// 然后可以将 seraddr 传递给 bind() 函数
bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));

TCP收端:

   1. socket 

   2. bind

        绑定套接字到本地的IP地址和端口,以便客户端能够找到并连接。

 

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


    功能:
        在套接字上绑定一个IP地址和端口号
    参数:
        sockfd:套接字文件描述符
        addr:绑定IP地址空间首地址
        addrlen:绑定IP地址的长度
    返回值:
        成功返回0 
        失败返回-1 

   3. listen 

  int listen(int sockfd, int backlog);


  功能:
    监听客户端发送的连接请求
    该函数不会阻塞
  参数:
    sockfd:套接字文件描述符
    backlog:允许等待的尚未被处理的三次握手请求的最大个数
  返回值:
    成功返回0 
    失败返回-1 

   4. accept 

 

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

功能:
    处理等待连接队列中的第一个连接请求
    该函数具有阻塞功能(如果没有人发送链接请求,会阻塞等待)
  参数:
    socket:套接字文件描述符
    address:存放IP地址的空间首地址
    addrlen:存放IP地址大小空间首地址
  返回值:
    成功返回一个新的文件描述符
    失败返回-1 

   5. send 

   6. recv 

   7.close 

TCP通信 写一个客户端和服务端两者建立通信

/*************************************************************************
	> File Name: head.h
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月01日 星期一 20时19分06秒
 ************************************************************************/

#ifndef _HEAD_H
#define _HEAD_H

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#endif

服务端

/*************************************************************************
	> File Name: recv.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月01日 星期一 22时58分52秒
 ************************************************************************/

#include"head.h"

int main(void)
{
    int ret = 0;
    int sockfd = 0;
    int confd = 0;
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;
    struct sockaddr_in seraddr;

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = INADDR_ANY;//允许任何ip地址连接

    sockfd = socket(AF_INET,SOCK_STREAM,0);//创建一个基于IPV4的tcp套接字
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }

    ret = bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr)); //将创建的套接字绑定到指定的服务器地址 seraddr
    if(-1 == ret)
    {
        perror("fail to bind");
        return -1;
    }

    ret = listen(sockfd,10);//将套接字设置为监听模式  允许10个客户端连接请求排队
    if(-1 == ret)
    {
        perror("fail to listen");
        return -1;
    }

    confd = accept(sockfd,NULL,NULL);//接受一个客户端的连接请求 返回一个新的套接字文件描述符confd 用于与该客户端通信
    if(-1 == confd)
    {
        perror("fail to accept");
        return -1;
    }

    nsize = recv(confd,tmpbuff,sizeof(tmpbuff),0); //接收客户端数据
    if(-1 == nsize)
    {
        perror("fail to recv");
        return -1;
    }

    printf("RECV:%s\n",tmpbuff);

    memset(tmpbuff,0,sizeof(tmpbuff));       //清零 tmpbuff中的数据
    fgets(tmpbuff,sizeof(tmpbuff),stdin);                          //会有输入阻塞  等待用户输入
    tmpbuff[strcspn(tmpbuff,"\n")] ='\0';   // 消除 由fgets 自动产生的末尾的换行符
    nsize = send(confd,tmpbuff,strlen(tmpbuff),0);//等待用户输入并发送给客户端
    if(-1 == nsize)
    {
        perror("fail to send");
        return -1;
    }
    close(confd);
    close(sockfd);

    return 0;
}

客户端

/*************************************************************************
	> File Name: send.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月01日 星期一 20时25分08秒
 ************************************************************************/
/***
*客户端
*/
#include"head.h"

int main(void)
{
    int ret = 0;
    int sockfd = 0;
    struct sockaddr_in seraddr;
    char tmpbuff[1024] = {0};
    ssize_t nsize =0;

    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }
     //初始化服务器地址
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = inet_addr("192.168.1.151");  //本机的ip地址

    /* 连接服务器*/
    ret = connect(sockfd,(struct sockaddr*)&seraddr,sizeof(seraddr));//建立tcp连接
    if(-1 == ret)
    {
        perror("fail to connect");
        return -1;
    }
   
    /*等待用户输入并发送给服务器*/
    gets(tmpbuff);
    nsize = send(sockfd,tmpbuff,strlen(tmpbuff),0);//发送数据
    if(-1 == nsize)
    {
        perror("fail to send");
        return -1;
    }
    /*
    *接收服务器数据
    * */
    memset(tmpbuff,0,sizeof(tmpbuff));
    nsize = recv(sockfd,tmpbuff,sizeof(tmpbuff),0);//接收数据
    if(-1 == nsize)
    {
        perror("fail to recv");
        return -1;
    }

    printf("RECV:%s\n",tmpbuff);

    close(sockfd);

    return 0;
}

 实现效果

TCP通信-LMLPHP

 通过TCP实现文件发送接收

发送端 

/*************************************************************************
	> File Name: send.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月01日 星期一 23时43分33秒
 ************************************************************************/

#include"head.h"

int main(void)
{
    int ret = 0;
    int sockfd =0;
    struct sockaddr_in recvaddr;
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;
    ssize_t nret = 0;
    int fd = 0;
    printf("Enter filename:\n");
    gets(tmpbuff);

    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.1.151");

    ret = connect(sockfd,(struct sockaddr*)&recvaddr,sizeof(recvaddr));
    if(-1 == ret)
    {
        perror("fail to connect");
        return -1;
    }

    nsize = send(sockfd,tmpbuff,strlen(tmpbuff),0);
    if(-1 == nsize)
    {
        perror("fail to send");
        return -1;
    }
    
    sleep(1);
    //打开文件
    fd = open(tmpbuff,O_RDONLY);
    if(-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
    //循环读取数据并发送
    while(1)
    {
        memset(tmpbuff,0,sizeof(tmpbuff));//确保读取之前tmpbuff 已经清零
        nret = read(fd,tmpbuff,sizeof(tmpbuff));// 使用read读取   tmpbuff大小(1024)字节的数据
        if(nret<0)
        {
            break;
        }

        nsize = send(sockfd,tmpbuff,nret,0);
        if(-1 == nsize)
        {
            perror("fail to send");
            return -1;
        }
    }
    close(fd);
    close(sockfd);
}

接收端

/*************************************************************************
	> File Name: recv.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月02日 星期二 00时01分51秒
 ************************************************************************/

#include"head.h"
int main(void)
{
    int ret = 0;
    int sockfd = 0;
    int confd = 0;
    ssize_t nsize =0;
    struct sockaddr_in recvaddr;
    char tmpbuff[1024] = {0};
    int fd = 0;

    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = INADDR_ANY;

    ret = bind(sockfd,(struct sockaddr*)&recvaddr,sizeof(recvaddr));
    if(-1 == ret)
    {
        perror("fail to bind");
        return -1;
    }

    ret = listen(sockfd,10);
    if(-1 == ret)
    {
        perror("fail to listen");
        return -1;
    }

    confd = accept(sockfd,NULL,NULL);
    if(-1 == confd)
    
        perror("fail to accept");
        return -1;
    }

    nsize = recv(confd,tmpbuff,sizeof(tmpbuff),0);
    if(-1 == nsize)
    {
        perror("fail to recv");
        return -1;
    }
   //打开文件 如果文件不存在则创建  如果文件之前存在 则清空   ,写入模式
    fd = open(tmpbuff,O_WRONLY|O_CREAT|O_TRUNC,0664);
    if(-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
    //循环接收数据并写入文件
    while(1)
    {
        nsize = recv(confd,tmpbuff,sizeof(tmpbuff),0);
        if(-1 == nsize)
        {
            perror("fail to recv");
            return -1;
        }
        else if(0 == nsize)
        {
            break;
        }

        write(fd,tmpbuff,nsize);
    }

    close(fd);
    close(confd);
    close(sockfd);

    return 0;
}
04-03 04:05