tcp通信,客户端服务端

进行过程 

//TCP通信的流程

//服务器端(被动接受连接的角色)

1.创建一个用于监听的套接字

        -监听:监听有客户端的连接

        -套接字:这个套接字其实就是一个文件描述符

2.将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息)

        -客户端连接服务器的时候使用的就是这个IP和端口

3.设置监听,监听的fd开始工作

4.阻塞等待,当有客户端发起连接,解除阻塞,接受客户端的连接,会得到一个和客户端通信的套接字(fd)

5.通信

        -接收数据

        -发送数据

6.通信结束,断开连接

//客户端

1.创建一个用于通信的套接字(fd)

2.连接服务器,需要指定连接的服务器和IP和端口

3.连接成功了,客户端可以直接和服务器端通信

             -接收数据

             -发送数据

4.通信结束,断开连接

 

字节序转换函数

发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端直到对方传送过来的数据总数采用大端字节序,所以接收端可以自身采用的字节序决定是否对接收到的数据进行转换(小端机转换,大端机不转换)

网络字节序采用大端

 

 

IP地址转化

 比如用点分十进制字符串表示 IPv4 地址,以及用 十六进制字符串表示 IPv6 地址。但编程中我们需要先把它们转化为整数(二进制数)方能使用。而记录 日志时则相反,我们要把整数表示的 IP 地址转化为可读的字符串

 

 

tcp/ip协议族

struct sockaddr_in
  {
    sa_family_t sin_family;     /*__SOCKADDR_COMMON (sin_)*/
    in_port_t sin_port;			/* Port number.  */
    struct in_addr sin_addr;		/* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
			   __SOCKADDR_COMMON_SIZE -
			   sizeof (in_port_t) -
			   sizeof (struct in_addr)];
  };


struct in_addr
{
    in_addr_t s_addr;
};

 端口复用

 

 套接字函数

 

 

 show me the Code

客户端代码

#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

using namespace std;

int main() {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1) {perror("socket"); return -1;}

    struct sockaddr_in seaddr;
    inet_pton(AF_INET, "127.0.0.1",&seaddr.sin_addr.s_addr);
    seaddr.sin_family = AF_INET;
    seaddr.sin_port = htons(9999);
    int ret = connect(fd, (struct sockaddr*)&seaddr,sizeof(seaddr));    
    if (ret == -1) {perror("connect"); return -1;}

    while(1) {
        char sendBuf[1024] = {0};
        fgets(sendBuf, sizeof(sendBuf), stdin);

        write(fd, sendBuf, strlen(sendBuf) + 1);

        //接收
        int len = read(fd, sendBuf, sizeof(sendBuf));
        if (len==-1) {
            perror("read");
            return -1;
        }else if(len > 1) {
            printf("read buf = %s\n", sendBuf);
        }else {
            printf("服务器已经断开连……\n");
            break;
        }
    }

    close(fd);
    return 0;


    return 0;
}

服务端代码

#include <stdio.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {
    //创建socket
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in seraddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_addr.s_addr = INADDR_ANY;
    seraddr.sin_port = htons(9999);

    //端口复用,防止服务器重启时之前绑定的端口还没有释放
    //程序突然退出而系统没有释放端口
    int optval = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
    
    //绑定
    int ret = bind(lfd, (struct sockaddr*)&seraddr, sizeof(seraddr));
    if(ret == -1) {
        perror("bind");
        return -1;
    }

    //监听
    ret = listen(lfd, 8);
    if(ret == -1) {
        perror("listen");
        return -1;
    }

    //接收客户端连接
    struct sockaddr_in cliaddr;
    socklen_t len = sizeof(cliaddr);
    int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
    if(cfd == -1) {
        perror("accept");
        return -1;
    }

    //获取客户端信息
    char clilp[16];
    inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, clilp, sizeof(clilp));
    int cliPort = ntohs(cliaddr.sin_port);
    //printf("client's ip is%s, ans port is %d\n", clilp, cliPort);

    //接收客户端发来的数据
    char recvBuf[1024] = {0};
    while(1) {
        int len = recv(cfd, recvBuf, sizeof(recvBuf), 0);
        if(len == -1) {
            perror("recv");
            return -1;
        }else if(len == 0) {
            printf("客户端已经断开连接……\n");
            break;
        }else if(len > 0) {
            printf("read buf = %s\n", recvBuf);
        }

        char sendBuf[1024] = {0};
        fgets(sendBuf, sizeof(sendBuf), stdin);

        //大写字符串发送给客户端
        ret = send(cfd, sendBuf, strlen(sendBuf) + 1, 0);
        if(ret == -1) {
            perror("send");
            return -1;
        }
    }

    close(cfd);
    close(lfd);
    return 0;
}

在linux编译即可

g++  客户端.cpp -o a.out

g++  服务端.cpp -o b.out

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!以下是一个简单的C++ Qt TCP通信客户端服务端代码示例: 服务端代码: ```cpp #include <QTcpServer> #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTcpServer server; server.listen(QHostAddress::Any, 1234); // 监听所有地址的1234端口 QObject::connect(&server, &QTcpServer::newConnection, [&]() { QTcpSocket *socket = server.nextPendingConnection(); QObject::connect(socket, &QTcpSocket::readyRead, [&]() { QByteArray data = socket->readAll(); qDebug() << "接收到客户端消息:" << data; socket->write("服务器已接收到消息"); socket->flush(); }); }); return a.exec(); } ``` 客户端代码: ```cpp #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTcpSocket socket; socket.connectToHost("localhost", 1234); // 连接到本地主机的1234端口 QObject::connect(&socket, &QTcpSocket::connected, [&]() { qDebug() << "已连接到服务器"; socket.write("Hello Server"); socket.flush(); }); QObject::connect(&socket, &QTcpSocket::readyRead, [&]() { QByteArray data = socket.readAll(); qDebug() << "接收到服务器消息:" << data; socket.close(); }); return a.exec(); } ``` 这个示例中,服务端监听在1234端口,客户端连接到本地主机的1234端口。当客户端连接成功后,客户端会发送"Hello Server"的消息给服务端服务端接收到消息后会回复"服务器已接收到消息"给客户端客户端接收到回复后会打印出来并关闭连接。 你可以根据需要修改代码来满足你的具体需求。希望对你有帮助!如有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未央吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值