TCP—传输控制协议

TCP是一种面向连接的传输层协议,它能提供高可靠性通信

即数据无误、数据无丢失、数据无失序、数据无重复到达的通信

适合于对传输质量要求较高的通信,主要用于通讯软件用户登录账户管理等方面

流程 —基础版

服务器

socket:创建一个用与链接的套接字

头文件:

#include <sys/types.h> 
#include <sys/socket.h>
格式

int socket(int domain, int type, int protocol);

返回值

成功返回一个用于连接的文件描述符,失败返回-1;

int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 0 自动匹配协议
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }

 填充通信结构体

    struct sockaddr_in saddr,caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    //"8880" atoi函数:将数字字符转化为数值
    //saddr.sin_addr.s_addr = inet_addr(argv[1]);

bind:绑定自己的ip地址和端口

头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

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

成功返回0,失败返回-1;

 if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }

listen:监听,将主动套接字转为被动套接字

 头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

int listen(int sockfd, int backlog);
返回值

成功返回0,失败返回-1;

 if (listen(sockfd, 5) < 0)
    {
        perror("listen error.");
        return -1;
    }

accept:阻塞等待客户端链接,链接成功返回一个用于通信套接字

头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

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

成功返回一个用于通信的文件描述符,失败返回-1;

  int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }

recv:接收消息

头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

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

成功返回收到的字节数;另一边关闭时返回0;失败返回-1;

            int ret = recv(acceptfd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err.");
                return -1;
            }
            else if (ret == 0)
            {
                printf("client exit.\n");
                break;
            }
            else
            {
                printf("buf:%s\n", buf);
            } 

send:发送消息

头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

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

成功返回发送的字节数;失败返回-1;

send(sockfd,buf,sizeof(buf),0); 

close:关闭文件描述符

头文件

#include <unistd.h>
格式

int close(int fd);
返回值

成功返回0;失败返回-1;

 close(sockfd);

 

客户端:

socket:创建一个套接字

填充结构体:填充服务器的ip和端口

connect:阻塞等待链接服务器

头文件

#include <sys/types.h> 
#include <sys/socket.h>
格式

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

连接成功返回0;失败返回-1;

  int d=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    if(d<0)
    {
        perror("connect err。");
        return -1;
    }

recv/send:接收/发送消息

close:关闭

整体代码

服务器端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>


int main(int argc, char const *argv[])
{
    //1.创建流式套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 0 自动匹配协议
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    printf("socket ok:%d\n", sockfd);
    //定义一个ipv4的通信结构体
    struct sockaddr_in saddr,caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    //"8880" atoi函数:将数字字符转化为数值
    //saddr.sin_addr.s_addr = inet_addr(argv[1]);//ip地址
    
    //设置自动获取本机ip。
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    

    socklen_t len=sizeof(caddr);

    //2.绑定bind
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }
    printf("bind ok.\n");
    //3.监听  listen
    if (listen(sockfd, 5) < 0)
    {
        perror("listen error.");
        return -1;
    }
    printf("listen ok.\n");
    while (1)
    {
        //4.阻塞等待链接,成功得到一个用于通信的文件描述符
        int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("accept ok %d\n", acceptfd);
        printf("client ip = %s port=%d \n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));

        //通信 收
        char buf[128];
        while (1)
        {
            bzero(buf, sizeof(buf));
            int ret = recv(acceptfd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err.");
                return -1;
            }
            else if (ret == 0)
            {
                printf("client exit.\n");
                break;
            }
            else
            {
                printf("buf:%s\n", buf);
            }
        }
        close(acceptfd);
    }
    close(sockfd);
    return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>


int main(int argc, char const *argv[])
{
    if(argc != 3)
    {
        printf("please input %s <ip> <port>\n",argv[0]);
        return -1;
    }
    //创建流式套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    printf("socket ok:%d\n",sockfd);
    //填充服务器端ip和端口(ipv4)
    struct sockaddr_in saddr;
    saddr.sin_family=AF_INET;//通信类型  ipv4
    saddr.sin_port=htons(atoi(argv[2]));
    // atoi函数:将数字字符转化为数值
    saddr.sin_addr.s_addr=inet_addr(argv[1]);
    //请求连接服务器
    int d=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    if(d<0)
    {
        perror("connect err。");
        return -1;
    }
    printf("connect ok \n");
    //循环发送 
    char buf[128];
    int ret;
    while(1)
    {
        bzero(buf,sizeof(buf));
        fgets(buf,128,stdin);
        //实际获取的最大数据长度size-1,补'\0',
        //遇到'\n'截至,同时会获取'\n'.        
        if (!strcmp("quit\n", buf))//可不用if,运行时直接用 ctrl +c退出
            break;
        if(buf[strlen(buf)-1] == '\n')
            buf[strlen(buf)-1] = '\0';
        send(sockfd,buf,sizeof(buf),0);
        
    }
    close(sockfd);
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值