linux TCP通信【socket套接字】

一、Socket

  • Socket 在 Linux 环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。
  • 在 TCP/IP 协议中,“ IP 地址+ TCP 或 UDP 端口号 ” 唯一标识网络通讯中的一个进程。“ IP 地址+ 端口号 ”就对应一个 socket。欲建立连接的两个进程各有一个 socket 来标识,那么这两个 socket 组成的 socket pair 就唯一标识一个连接。因此可以用 socket 来描述网络连接的一对一关系。
  • 在网络通信中,套接字一定是成对出现的。
    如图为套接字通信原理:
    在这里插入图片描述




    TCP通信socket模型创建流程图:
    在这里插入图片描述


二、使用的函数

  • int socket( int domain, int type, int protocal);
    • domain:
      • AF_INET 使用 IPv4 的地址
      • AF_INET6 使用 IPv6 的地址
    • type:
      • SOCK_STREAM 这协议是按照顺序的、可靠的、数据完整的基于字节流的连接。使用 TCP 来进行传输。
      • SOCK_DGRAM 是无连接的、固定长度的传输调用。是不可靠的,使用UDP。
    • protocol:
      • 传 0 表示使用默认协议。
    • 返回值:
      • 成功:返回指向新创建的socket 的文件描述符
      • 失败:返回 -1

  • int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    • sockfd:
      • socket 文件描述符
    • addr:
      • 构造出 IP 地址加端口号
    • addrlen:
      • sizeof(addr) 长度
    • 返回值:0/ -1

  • int listen( int sockfd, int backlog);
    • sockfd:
      • socket 文件描述符
    • backlog:
      • 排队建立3次握手队列和刚刚建立3次握手队列的连接数和

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

    • sockdf:
      • socket 文件描述符
    • addr:
      • 传出参数,返回链接客户端地址信息,含 IP 地址和端口号
    • addrlen:
      • 传入传出参数, 传入sizeof(addr)大小, 函数返回时返回真正接收到地址结构体的大小。
    • 返回值:
      • 成功返回一个新的 socket 文件描述符,用于和客户端通信,失败 -1。

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

    • sockdf:
      • socket 文件描述符
    • addr:
      • 传入参数,指定服务器端地址信息,含 IP 地址和端口号。
    • addrlen:
      • 传入参数,传入 sizeof(addr) 大小
    • 返回值: 0/ -1


三、代码

先运行服务端,再运行客户端

服务端

#include<stdio.h>
#include<ctype.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>

#define SERV_PORT 9527

void sys_err(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char *argv[]){
    
    int lfd = 0, cfd = 0;
    int ret;
    char buf[BUFSIZ], client_IP[1024];
    
    struct sockaddr_in serv_addr, clit_addr;
    socklen_t clit_addr_len;
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1){
        sys_err("socket error");
    }
    
    bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    
    listen(lfd, 128);
    
    clit_addr_len = sizeof(clit_addr);
    cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
    if(cfd == -1){
        sys_err("accept error");
    }
    
    printf("client ip:%s port:%d\n", inet_ntop(AF_INET, &clit_addr.sin_addr, client_IP, sizeof(client_IP)), ntohs(clit_addr.sin_port));
    
    while(1){
        ret = read(cfd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, ret);
        
        for(int i=0; i<ret; i++){
            buf[i] = toupper(buf[i]);
        }
        
        write(cfd, buf, ret);
    }
    
    close(lfd);
    close(cfd);
   
    return 0;
}

客户端

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>

#define SERV_PORT 9527

void sys_err(const char *str){
    
    perror(str);
    exit(1);
}

int main(int argc, char *argv[]){
    int cfd;
    int conter = 0;
    char buf[BUFSIZ];
    
    struct sockaddr_in serv_addr;   //服务器地址结构
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
    
    cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(cfd == -1){
        sys_err("socket error");
    }
    
    int ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if(ret != 0){
        sys_err("connect err");
    }
    
    while(--conter){
        write(cfd, "hello\n", 6);
        sleep(1);
        ret = read(cfd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, ret);
    }
    
    close(cfd);
    
    return 0;
}

效果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值