网络编程:TCP

一、tcp编程

注意

1.数据本身有顺序

2.发送和接收次数不需要对应


1. C/S 模式

==》服务器/客户端模型

server:socket()-->bind()--->listen()-->accept()-->recv()-->close()

client:socket()-->connect()-->send()-->close();

int on = 1;

setsockopt(listfd, SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

2. 服务器端

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

1)socket()

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

功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain 地址族,PF_INET == AF_INET ==>互联网程序
PF_UNIX == AF_UNIX ==>单机程序

type 套接字类型:
SOCK_STREAM 流式套接字 ===》TCP
SOCK_DGRAM 用户数据报套接字===>UDP
SOCK_RAW 原始套接字 ===》IP

protocol 协议 ==》0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id

失败 -1;

2)bind()

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

功能:如果该函数在服务器端调用,则表示将 参数1相关的文件描述符文件 与参数2指定的接口地址关联,用于从该接口接受数据。

如果该函数在客户端调用,则表示要将 数据从参数1所在的描述符中 取出 并从 参数2所在的接口设备上 发送出去。

注意:如果是客户端,则该函数可以省略,由默认接口发送数据。

参数:sockfd 之前通过socket函数创建的文件描述符,套接字id

my_addr 是物理接口的结构体指针。表示该接口的信息

struct sockaddr 通用地址结构

{

u_short sa_family; 地址族

char sa_data[14]; 地址信息

};

转换成网络地址结构如下:

struct _sockaddr_in ///网络地址结构

{

u_short sin_family; 地址族

u_short sin_port; ///地址端口

struct in_addr sin_addr; ///地址IP

char sin_zero[8]; 占位

};

struct in_addr

{

in_addr_t s_addr;

}

socklen_t addrlen: 参数2 的长度。

返回值:成功 0

失败 -1;

3)listen()

int listen(int sockfd, int backlog);

功能:在参数1所在的套接字id上监听等待链接。

参数:sockfd 套接字id

backlog 允许链接的个数

返回值:成功 0

失败 -1;

4)accept()

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

功能:从已经监听到的队列中取出有效的客户端链接并接入到当前程序。

参数:sockfd 套接字id

addr 如果该值为NULL ,表示不论客户端是谁都接入。

如果要获取客户端信息,则事先定义变量并传入变量地址,函数执行完毕将会将客户端
信息存储到该变量中。

addrlen 参数2的长度,如果参数2为NULL,则该值也为NULL;

如果参数不是NULL,&len,
一定要写成len = sizeof(struct sockaddr);

返回值:成功 返回一个用于通信的新套接字id;

从该代码之后所有通信都基于该id

失败 -1;

5)接收函数/发送函数

read()/write () ///通用文件读写,可以操作套接字。
recv(,0) /send(,0) ///TCP 常用套机字读写

recvfrom()/sendto() ///UDP 常用套接字读写
ssize_t recv(int sockfd, void *buf, size_t len,int flags);

功能:从指定的sockfd套接字中以flags方式获取长度为len字节的数据到指定的buff内存中。

参数:sockfd 如果服务器则是accept的返回值的新fd
如果客户端则是socket的返回值旧fd

buff 用来存储数据的本地内存,一般是数组或者动态内存。

len 要获取的数据长度

flags 获取数据的方式,0 表示阻塞接受

返回值:成功 表示接受的数据长度,一般小于等于len

失败 -1;

6)close()

===>关闭指定的套接字id;

3. 客户端

1)connect()

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

功能:该函数固定有客户端使用,表示从当前主机向目标主机发起链接请求。

参数:sockfd 本地socket创建的套接子id

addr 远程目标主机的地址信息

addrlen 参数2的长度

返回值:成功 0

失败 -1;

2)send()

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

功能:从msg所在的内存中获取长度为len的数据以flags方式写入到sockfd对应的套接字中。

参数:sockfd 如果是服务器则是accept的返回值新fd
如果是客户端则是sockfd的返回值旧fd

msg 要发送的消息

len 要发送的消息长度

flags 消息的发送方式

返回值:成功 发送的字符长度

失败 -1;


ser.c

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
   
    //监听套接字
    int listfd =  socket(AF_INET,SOCK_STREAM, 0);
    if(-1 == listfd)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(listfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    //同一时刻三次握手排队数
    listen(listfd,3);
    socklen_t  len = sizeof(cli);
    //通信套接字 
    int conn = accept(listfd,(SA)&cli,&len);
    if(-1 == conn)
    {
        perror("accept");
        exit(1);
    }

    while(1)
    {
        char buf[512]={0};
        int rd_ret = recv(conn,buf,sizeof(buf),0);
        if(rd_ret<=0)
        {// 0  对方断开连接 -1 错误
            break;
        }
        time_t tm;
        time(&tm);
        sprintf(buf,"%s %s",buf,ctime(&tm));
        send(conn,buf,strlen(buf),0);
        
    }
    close(listfd);
    close(conn);
    return 0;
}

cli.c

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
typedef struct sockaddr* (SA);

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int ret = connect(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("connect");
        exit(1);
    }
    while(1)
    {
        char buf[512]="hello,this is tcp test";
        send(sockfd,buf,strlen(buf),0);
        bzero(buf,sizeof(buf));
        recv(sockfd,buf,sizeof(buf),0);
        printf("buf :%s\n",buf);
        sleep(1);
    }
    close(sockfd);
    return 0;
}

tcp发文件,图片------cp 1.png 2.png

ser.c

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
   
    //监听套接字
    int listfd =  socket(AF_INET,SOCK_STREAM, 0);
    if(-1 == listfd)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(listfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    //同一时刻三次握手排队数
    listen(listfd,3);
    socklen_t  len = sizeof(cli);
    //通信套接字 
    int conn = accept(listfd,(SA)&cli,&len);
    if(-1 == conn)
    {
        perror("accept");
        exit(1);
    }
    int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);
    if(-1 ==fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        char buf[512]={0};
        int rd_ret = recv(conn,buf,sizeof(buf),0);
        if(rd_ret<=0)
        {// 0  对方断开连接 -1 错误
            break;
        }
        write(fd,buf,rd_ret);
        bzero(buf,sizeof(buf)); 
        strcpy(buf,"123");
        send(conn,buf,strlen(buf),0);
        
    }
    close(fd);
    close(listfd);
    close(conn);
    return 0;
}

cli.c

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    //host to net long 
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");

    int ret = connect(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("connect");
        exit(1);
    }
    int fd = open("/home/linux/1.png",O_RDONLY);
    if(-1 ==fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        char buf[512]={0};
        int rd_ret = read(fd,buf,sizeof(buf));
        if(rd_ret<=0)
        {
            break;
        }
        send(sockfd,buf,rd_ret,0);
        bzero(buf,sizeof(buf));
        recv(sockfd,buf,sizeof(buf),0);
    }
    close(fd);
    close(sockfd);
    return 0;
}
相关推荐
神技圈子17 分钟前
【linux】推荐个自研的工具:一键式自动生成并更新ssl证书
网络·网络协议·ssl
鲁鲁51725 分钟前
数据库常见的安全特性有哪些
网络·数据库·安全
小龙在慢慢变强..2 小时前
常见的负载均衡
linux·运维·网络·python·ubuntu
Super-Yb4 小时前
提升音视频应用流畅度的关键:网络流量分析与监控
服务器·网络·音视频·网络流量分析·全流量回溯分析
等保桃夭夭5 小时前
“网络安全等级保护测评入门:基础概念与重要性“
网络·安全·web安全
码哝小鱼5 小时前
使用tcpkill断开异常tcp连接
网络·网络协议·tcp/ip
qq_200337396 小时前
为确保阻塞缺陷的解决时间要求得到有效执行,可以采取以下措施:
运维·服务器·网络
小马同志( ̄^ ̄)ゞ6 小时前
正在执行脚本时,网络断开了该怎么办?
网络
91数据恢复6 小时前
守护数据安全:.rmallox勒索病毒的防范与应对策略
网络·安全·web安全
奋斗的小青年I6 小时前
Windows无需管理员权限,命令轻松修改IP和DNS
运维·windows·网络协议·tcp/ip·系统架构·云计算