socket编程实战之“回声客户端/服务器端”

本文详细介绍了如何使用C++编写TCPsocket示例,包括服务器端的地址绑定、监听和客户端的连接、数据发送与接收。展示了客户端向服务器发送消息,服务器接收并返回的过程。
摘要由CSDN通过智能技术生成

1.示例描述

按照第一篇文章的框架,使用相应的函数来编写一个基于TCP的socket示例,实现不同主机的通信,具体表现为:客户端主机运行程序,可以发送消息给服务器端;服务器端主机运行程序,能够接收到消息并打印出来,并且原封不动的将消息返还给客户端, 客户端能显示服务器端的响应。
下面分别从服务器端和客户端来实现socket程序。

2.服务器端

#include<iostream>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string>
#define BUFF_SIZE 1024
int main(){
    //使用socket函数,创建套接字。对于TCP的服务器端,该套接字是服务器端的 看门狗
    //PF_INET:IPv4协议簇  SOCK_STREAM:面向连接的
    //IPv4协议簇下的SOCK_STREAM只有TCP协议,所以第三个参数可以填0
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        std::cout << "create socket error" << std::endl;
        return -1;
    }
    
    //注册地址信息
    sockaddr_in addr;//c++11 可以忽略struct关键字
    addr.sin_family = AF_INET;//地址协议族:IPv4
    //使用htonl将主机字节序转为网络字节序
    addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY自动获取运行服务器端的主机IP地址
    addr.sin_port = htons(8080);//使用htons函数,将端口号转为网络字节序

    //使用bind函数,将地址绑定到套接字
    if (bind(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
    {
        std::cout << "bind socket error" << std::endl;
        return -1;
    }
    
    //使用listen函数,开启套接字监听,队列长度为3
    if (listen(sockfd, 3) == -1)
    {
        std::cout << "listen socket error" << std::endl;
        return -1;
    }
    std::cout << "waiting for connecting..." << std::endl;

	//注册一个新地址
    sockaddr_in new_addr;
    socklen_t new_len = sizeof(new_addr);
    while (true)
    {
        //使用accept函数,将新地址注册到一个新的套接字上,该套接字才是用来通信的
        int new_sockfd = accept(sockfd, (sockaddr*)&new_addr, &new_len);
        if (new_sockfd == -1)
        {
            std::cout << "accept socket error" << std::endl;
            return -1;        
        }
        std::cout << "socket connect successfully..." << std::endl;
        
        //使用read和write函数,实现数据交互
        int size = 0;
        char buff[BUFF_SIZE];//开辟缓冲区
        //使用read函数,通过新的套接字从通道里面 读取数据到本地缓冲区
        while ((size = read(new_sockfd, buff, BUFF_SIZE)) !=0 )
        {
            if (size == -1)
            {
                std::cout << "read socket error" << std::endl;
                return -1;   
            }
            std::cout << "收到来自客户端的消息: " << buff << std::endl;
            
            //使用write函数,通过新的套接字将本地缓冲区的数据 写到通道里面
            size = write(new_sockfd, buff, size);
            if (size == -1)
            {
                std::cout << "write socket error" << std::endl;
                return -1;   
            }
        }
        
        //客户端断开连接
        std::cout << "connection exit..." << std::endl;
        //使用close函数,关闭套接字
        close(new_sockfd);
    }
    
    //关闭看门狗套接字
    close(sockfd);
    return 0;
}

3.客户端

#include<iostream>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string>
#include<stdio.h>
#include<string.h>

//宏定义服务器端的IP地址
#define IP "192.168.120.100"

int main(){
    //使用socket函数,创建套接字。对于TCP的客户端,该套接字是直接用来通信的
    //PF_INET:IPv4协议簇  SOCK_STREAM:面向连接的
    //IPv4协议簇下的SOCK_STREAM只有TCP协议,所以第三个参数可以填0
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        std::cout << "create socket error" << std::endl;
        return -1;
    }
    
    //注册地址信息
    sockaddr_in addr;//c++11 可以忽略struct关键字
    addr.sin_family = AF_INET;//地址协议族:IPv4
    //使用inet_addr,将点分十进制的IP地址字符串转为32位整型
    addr.sin_addr.s_addr = inet_addr(IP);//服务器端的IP地址
    addr.sin_port = htons(8080);//使用htons函数,转为网络字节序,与服务器端的端口号一致

    //使用connect函数,使用要连接的服务器端地址信息通过套接字进行连接
    if (connect(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
    {
        std::cout << "connect socket error" << std::endl;
        return -1;
    }
    std::cout << "connected..." << std::endl;
    
    //数据交互
    std::cout << "开始输入..." << std::endl;
    while (true)
    {   
    	//使用C++风格的字符串输入
    	std::string msg;
        std::cout << "(输入q结束连接): ";
        getline(std::cin, msg);
        if (msg == "q")
        {
            std::cout << "输入结束...." << std::endl;
            break;
        }
		
		//使用write函数,通过套接字将本地缓冲区的数据 写到通道里面
        int size = write(sockfd, msg.c_str(), sizeof(msg));
        if (size == -1)  
        {
            std::cout << "write socket error" << std::endl;
            return -1;
        }

        int read_all_size = 0;
        //读完写入大小的字节为止
        char buff[BUFSIZ];//开辟接收缓冲区
        while (read_all_size < size)
        {
            //使用read函数,通过套接字从通道里面 读取数据到本地缓冲区
            int read_size = read(sockfd, &buff[read_all_size], BUFSIZ-1);
            if (read_size == -1)
            {
                std::cout << "read socket error" << std::endl;
                return -1;
            }
            read_all_size += read_size;
        }
        //添加终止符,使用C风格字符串
        buff[read_all_size] = 0;
        std::cout << "收到来自服务端的消息: " << buff <<std::endl;
    }
    //使用close函数,关闭套接字
    close(sockfd);
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值