简单的Tcp服务器

TCP客户端实例程序

文件结构

  • 源代码文件目录(src)

    这里有main.cpp,是服务器端程序

  • 头文件目录(include)

    各种.h文件

  • 实例程序文件目录(test)

    这里写一个客户端连接程序

  • 项目构建文件(Makefile)

    完成项目的编译

头文件

include/base.h

c++ 复制代码
#ifndef __BASE__H
#define __BASE__H

#define BUFFSIZE    64

#endif

TCP服务器端

网络编程的主要内容其实就是在服务器端,要实现最基础的 TCP 服务器

src/main.cpp

cpp 复制代码
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>
#include "base.h"
using namespace std;
// 错误处理函数
static void error_handle(string opt,string message){
    perror(opt.c_str());
    cout << message << endl;
    exit(1);
}
int main(int argc, char *argv[]){//argc是参数个数
    //参数需要2个:运行文件+端口
    if(argc < 2){       
        cout << "less" << argv[0] << "port" << endl;
        exit(1);                        
    }
    //创建套接字
    int serve_sock = socket(PF_INET, SOCK_STREAM, 0);   
    if(serve_sock==-1){
        error_handle("socket", "socket() error");
    }
    //绑定地址
    struct sockaddr_in serve_addr;
    serve_addr.sin_family = AF_INET;
    //htonl---host to net long
    //将一个32位的主机字节序变成网络字节序
    serve_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serve_addr.sin_port = htons(atoi(argv[1]));
    //返回指针要传地址,而且要强制类型转换成sockaddr*类型
    int ret = bind(serve_sock, (struct sockaddr *)&serve_addr, sizeof(serve_addr));
    if(ret==-1){
        error_handle("bind", "bind() error");
    }
    //监听
    if(listen(serve_sock,5)==-1){
        error_handle("listen", "listen() error");  
    }
    //accept--接受客户端的请求
    int client_sock;
    struct sockaddr_in client_addr;
    socklen_t client_addr_size=sizeof(client_addr);
    //while(1)循环应答
    while(1){
        client_sock = accept(serve_sock, (struct sockaddr *)&client_addr, &client_addr_size);
        if(client_sock ==-1){
            continue;//接受新的请求
        }
        //接收新的客户端请求,进行客户端数据处理
        //inet_ntoa():将一个网络字节序的IP地址转化为点分十进制的IP地址(字符串)。
        cout << "Accept New Client : " << inet_ntoa(client_addr.sin_addr) << \
                           ", port : " << ntohs(client_addr.sin_port) << std::endl;
        cout << "Start Recv Client Data........." << endl;
        /*传输信息*/
        char message[BUFFSIZE];
        memset((void *)&message, 0, BUFFSIZE);//传指针
        int MessageLen;
        //读取客户端的请求数据
        while((MessageLen=read(client_sock,message,BUFFSIZE))!=0){
            cout << "Server recv from Client:" << message << endl;
            //将消息回传给客户端
            write(client_sock, message, MessageLen);
            //清空消息
            memset(message, 0, BUFFSIZE);
        }
        close(client_sock);
    }
    //服务器关闭
    close(serve_sock);
    return 0;
}
    

客户端

test/tcpClient.cpp

c++ 复制代码
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>
#include "base.h"
using namespace std;
// 出错调用函数
static void error_handle(std::string opt, std::string message)
{
    //根据errno值获取失败原因并打印到终端
    perror(opt.c_str());
    std::cout << message << std::endl;
    exit(1);
}
int main(int argc,char* argv[]){
    if(argc < 3){
        cout << "Input IP and Port!" << endl;
    }
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock==-1){
        error_handle("socket", "socket() error");
    }
    //向服务器请求连接
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));
    int ret =connect(sock,(struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if(ret==-1){
        error_handle("connect", "connect() error");
    }
    cout << "connect success!!" << endl;
    //数据处理
    char message[BUFFSIZE];
    while (1){
        cout << "Please Input Message(Q to quit) : " << endl;
        cin >> message;
        if((!strcmp(message, "q")) || (!strcmp(message, "Q"))){
            break;
        }
        //把数据发送给服务端
        write(sock,message,strlen(message));
        //读取u服务端回传的消息
        int len = read(sock, message, BUFFSIZE - 1);
        message[len] = 0;
        cout << "echo message:" << message << endl;
    }
    close(sock);
    return 0;
}

Makefile

makefile 复制代码
pwd=${shell pwd}
src_dir=$(pwd)/src/
include_dir=$(pwd)/include/
test_dir=$(pwd)/test/

TARGET=TcpServer
########################## src section #################################
obj_src=${shell find $(src_dir) -name "*.cpp"}
OBJS=${patsubst %.cpp,%.o,$(obj_src)}
#添加测试文件的内容
test_src=${shell find ${test_dir} -name "*.cpp"}
TEST_OBJ=${patsubst %.cpp,%.o,${test_src}}
tests=${patsubst %.cpp,%,${test_src}}
####################### flag section ########################################
GXX=g++
CFLAGS=-I${include_dir}
#############################################################################
$(TARGET): $(OBJS)
	$(GXX) $(CFLAGS)  -o $@ $(OBJS)

%.o:%.cpp
	$(GXX) ${CFLAGS} -c -o $@ $<
#添加编译测试文件的规则使用
.PHONY: test
test: $(tests)
$(tests): $(TEST_OBJ)
	$(GXX) $(CFLAGS)  -o $@ $(TEST_OBJ)

$(TEST_OBJ): $(test_src)
	$(GXX) ${CFLAGS} -c $< -o $@


clean:
	rm $(TARGET)
	rm $(OBJS)
	rm ${TEST_OBJ}
	rm ${tests}

项目编译

注意如果头文件.h和.cpp在同一目录下可直接编译

如果头文件在同一目录文件夹,则必须在编译时指定头文件位置

😄本项目编译

在当前目录下make

在当前目录下make test

make clean可以去掉执行的文件

运行结果

服务端一次可以多个监听,但是只有一个可以通信
等当前客户端退出后,其他客户端可以与之通信,相当于阻塞

相关推荐
tomcsdn413 分钟前
SMTPman,smtp服务器高效邮件发送核心指南
服务器·邮件营销·邮件群发·smtp服务器·域名邮箱·邮件服务器·红人营销
知识都 知识都学杂了3 分钟前
VMware ESXi 不同版本下载
服务器
虚伪的空想家3 分钟前
HUAWEI A800I A2 aarch64架构服务器鲲鹏920开启虚拟化功能
linux·运维·服务器·显卡·npu·huawei·鲲鹏920
wayuncn5 分钟前
哈尔滨电商企业服务器托管方案
运维·服务器·数据库
D11_7 分钟前
在阿里云CentOS服务器上使用Certbot为Nginx配置SSL证书
服务器·阿里云·centos
梓沂10 分钟前
旧电脑变废为宝:打造低成本网络打印机服务器全记录
服务器·网络·php
刚刚觉醒的小菜鸡31 分钟前
ssh连接本地虚拟机
linux·服务器·ssh
持梦远方32 分钟前
Linux之认识理解目录
linux·运维·服务器
openHiTLS密码开源社区34 分钟前
【密码学实战】openHiTLS s_server命令行:搭建国密标准安全通信服务器
服务器·物联网·密码学·openhitls·tlcp·商用密码算法·dtlcp