TCP 简单通信

1.C++ TCP编程流程

服务端编程流程:

  1. 用 socket 创建一个套接字;
  2. 用 bind 给这个套接字绑定地址(即 ip+端口号)
  3. 调用 listen 把这个套接字置为监听状态;
  4. 调用 accept 函数从已完成连接队列中取出成功建立连接的套接字;
  5. 在这个新的套接字上调用 send、recv 来发送数据、接收数据;
  6. 最后调用 close 来断开连接释放资源即可。
    在这里插入图片描述
    客户端编程流程:
    与服务器不同,客户端并不需要 bind 绑定地址,因为端口号是系统自动分配的,而且客户端也不需要设置监听的套接字,因此也不需要 listen。客户端在用 socket 创建套接字后直接调用 connect 向服务器发起连接即可,connect 函数通知 Linux 内核完成 TCP 三次握手连接,最后把连接的结果作为返回值。成功建立连接后我们就可以调用 send 和 recv 来发送数据、接收数据,最后调用 close 来断开连接释放资源。

在这里插入图片描述
在这里插入图片描述

2.socket 常用API

地址结构:

struct sockaddr_in {
    short int sin_family; /* 地址族 */
    unsigned short int sin_port; /* 端口号 */
    struct in_addr sin_addr; /* ip地址 */
    unsigned char sin_zero[8];
};

socket 套接字初始化:

int socket( int domain, int type,int protocol)
/*
功能:创建一个新的套接字,返回套接字描述符
参数说明:
domain:域类型,指明使用的协议栈,如TCP/IP使用的是PF_INET,其他还有AF_INET6、AF_UNIX
type:指明需要的服务类型, 如
SOCK_DGRAM:数据报服务,UDP协议
SOCK_STREAM:流服务,TCP协议
protocol:一般都取0(由系统根据服务类型选择默认的协议)
*/

bind 绑定端口以及IP地址

int bind(int sockfd,struct sockaddr* my_addr,int addrlen)
/*
功能:为套接字绑定地址
TCP/IP协议使用sockaddr_in结构,包含IP地址和端口号,服务器使用它来指明熟知的端口号,然后等待连接
参数说明:
sockfd:套接字描述符,指明创建连接的套接字
my_addr:本地地址,IP地址和端口号
addrlen:地址长度
*/

listen 设置监听状态

int listen(int sockfd,int backlog)
/*
功能:
将一个套接字置为监听模式,准备接收传入连接。用于服务器,指明某个套接字连接是被动的监听状态。
参数说明:
Sockfd:套接字描述符,指明创建连接的套接字
backlog: linux内核2.2之前,backlog参数=半连接队列长度+已连接队列长度;linux内核2.2之后,backlog参数=已连接队列(Accept队列)长度
*/

accept函数从已完成连接队列中取出建立连接的

int accept(int sockfd, structsockaddr *addr, int *addrlen)
/*
功能:从已完成连接队列中取出成功建立连接的套接字,返回成功连接的套接字描述符。
参数说明:
Sockfd:套接字描述符,指明正在监听的套接字
addr:提出连接请求的主机地址
addrlen:地址长度
*/

send 发送数据

int send(int sockfd, const void * data, int data_len, unsigned int flags)
/*
功能:在TCP连接上发送数据,返回成功传送数据的长度,出错时返回-1。send会将数据移到发送缓冲区中。
参数说明:
sockfd:套接字描述符
data:指向要发送数据的指针
data_len:数据长度
flags:通常为0
*/

recv 函数接收数据;

int recv(int sockfd, void *buf, intbuf_len,unsigned int flags)
/*
功能:接收数据,返回实际接收的数据长度,出错时返回-1。
参数说明:
Sockfd:套接字描述符
Buf:指向内存块的指针
Buf_len:内存块大小,以字节为单位
flags:一般为0
*/

close 函数关闭连接

close(int sockfd)
/*
功能:撤销套接字。如果只有一个进程使用,立即终止连接并撤销该套接字,如果多个进程共享该套接字,将引用数减一,如果引用数降到零,则关闭连接并撤销套接字。
参数说明:
sockfd:套接字描述符
*/

客户端发送连接请求

int connect(int sockfd,structsockaddr *server_addr,int sockaddr_len)
/*
功能: 同远程服务器建立主动连接,成功时返回0,若连接失败返回-1。
参数说明:
Sockfd:套接字描述符,指明创建连接的套接字
Server_addr:指明远程端点:IP地址和端口号
sockaddr_len :地址长度
*/

3 编程

服务端程序;

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

using namespace std;

int main()
{
    int sever_fd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;//TCP/IP协议族
    server_sockaddr.sin_port = htons(8023);//端口号
    server_sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//ip地址,127.0.0.1是环回地址,相当于本机ip

    //bind,成功返回0,出错返回-1

    if(bind(sever_fd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    {
        perror("bind");
        exit(1);
    }

    if(listen(sever_fd,20)==-1)
    {
        perror("listen");
        exit(1);
    }

    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);

    int conn =accept(sever_fd,(struct sockaddr*)&client_addr,&length);
    if(conn<0)
    {
        perror("listen");
        exit(1);
    }
    cout<<"成功"<<endl;

    char buffer[10000];

    while(1){
        memset(buffer,0,sizeof(buffer));
        int len = recv (conn,buffer,sizeof(buffer),0);

        if(strcmp(buffer,"exit")==0 || len<=0)
            break;//打印数据,收到exit跳出循环

        cout<<"copy that"<<endl;

    }

    close(conn);
    close(sever_fd);
    return 0;
}

客户端:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
using namespace std;

int main()
{
    //定义sockfd
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);

    //定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;//TCP/IP协议族
    servaddr.sin_port = htons(8023);  //服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  //服务器ip

    //连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }
    cout<<"连接服务器成功!\n";

    char sendbuf[100];
    char recvbuf[100];
    while (1)
    {
        memset(sendbuf, 0, sizeof(sendbuf));
        cin>>sendbuf;
        send(sock_cli, sendbuf, strlen(sendbuf),0); //发送
        if(strcmp(sendbuf,"exit")==0)
            break;
    }
    close(sock_cli);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值