如何编写TCP服务器

客户端逻辑(不要绑定端口号)

1.用户输入数据,从标准输入输入一个字符串

2.把这个字符串发送给服务器

3.从服务器读取并返回结果

4.把响应写到标准输出上

 

服务器逻辑(绑定端口号)

1.启动(初始化)

2.进入死循环(事件循环)

    a)从socket中读取请求(Request)

    b)根据Request的内容计算生成Response

    c)把Response响应写回socket

 

 

服务器server.c

int main()
{
    //创建socket            IPV4      TCP              指定协议 不关心置0
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0)
    {
        perror("socket");

    }
    //定义两个addr_in 结构体
    struct sockaddr_in server_socket;
    struct sockaddr_in client_socket;
    //把server_socket置为零且包括‘\0’
    bzero(&server_socket,sizeof(server_socket));

    //初始化server_socket
    server_socket.sin_family = AF_INET;
    server_socket.sin_port = htons(_PORT_);//宏_PORT_被define成某个端口号
    //网络地址为INADDR_ANY,这个宏可以表示本地的任意IP地址
    //因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这个设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址;
    server_socket.sin_addr.s_addr = htonl(INADDR_ANY);//htohl表示主机字节序转网络字节序

    //将服务器的ip和端口号进行绑定
    if(bind(sock,(struct sockaddr *)&server_socket,sizeof(struct sockaddr_in)) < 0)
    {
        printf("bind error,error code is %d,error string is :%s\n",errno,strerror(errno));
        close(sock);
        return 1;
    }
    //绑定成功开始进入监听模式,_BACKLOG_ 正处于三次握手中的sock 定义为10
    if(listen(sock,_BACKLOG_) < 0)
    {
        printf("listen error,error code is %d,error string is %s\n",errno,strerror(errno));
        close(sock);
        return 2;
    }
    printf("bind and listen success,wait accept...\n");

    while(1)
    {
        socklen_t len = 0;
        //accept为阻塞式等待,若想改为非阻塞,可考虑添加IO多路复用机制,select,poll,epoll
        //三次握⼿完成后, 服务器调⽤accept()接受连接
        //若成功返回一个新的sock,专门用于与已连接的客户端通信
        int client_sock = accept(sock,(struct sockaddr *)&client_socket,&len);
        if(client_sock < 0)
        {
            printf("accept error, error is %d,errstring is %s\n",errno,strerror(errno));
            close(sock);
            return 3;
        }

        //开辟出一块新的缓存区用于存放IP地址 
        char buf_ip[INET_ADDRSTRLEN];
        memset(buf_ip,'\0',sizeof(buf_ip));
        // inet_ntop函数将用于网络传输的数值格式  转化为  点分十进制的ip地址      适用于IPV4,IPV6
        inet_ntop(AF_INET,&client_socket.sin_addr,buf_ip,sizeof(buf_ip));

        while(1)
        {
            //建立连接之后两端开始进行数据的交互式传输
            //创建缓存区并清空
            char buf[1024];
            memset(buf,'\0',sizeof(buf));
    
            //从sock中读取来自客户端的数据进buf
            read(client_sock,buf,sizeof(buf));
            
            //清空buf缓存区,往buf里面写服务器端响应 
            memset(buf,'\0',sizeof(buf));
            fgets(buf,sizeof(buf),stdin);
            buf[strlen(buf)-1] = '\0';
            //再把buf的数据往sock发送
            write(client_sock,buf,strlen(buf)+1);//在这里strlen(buf)+1和sizeof(buf)的区别
            printf("please wait...\n");

        }
    }
    close(sock);
    return 0;

}

 

客户端client.c

int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        printf("usage :client IP\n");
        return 1;
    }
    //存放命令行参数(ip地址)
    char *str = argv[1];
    char buf[1024];
    memset(buf,'\0',sizeof(buf));
    // 定义一个addr_in结构体作为服务器端的标识
    struct sockaddr_in server_sock;
    //创建一个sock
    int sock = socket(AF_INET,SOCK_STREAM,0);
  //初始化server_sock为0
    bzero(&server_sock,sizeof(server_sock));

    server_sock.sin_family = AF_INET;
    //把点分十进制整型转为网络字节序
    inet_pton(AF_INET,SERVER_IP,&server_sock.sin_addr);
    //主机字节序转为网络字节序
    server_sock.sin_port = htons(SERVER_PORT);
  //向服务器端发起连接请求
    int ret = connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock));
    if(ret < 0)
    {
        printf("connect failed...,errno is %d,errstring is %s\n",errno,strerror(errno));
    }
    printf("connect is success...\n");
  //进入事件循环
    while(1)
    {
        //从标准输入写数据进buf
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        write(sock,buf,sizeof(buf));
        //strncasecmp为忽略大小写的比较, 如果发现
        if(strncasecmp(buf,"quit",4) == 0)
        {
            //如果发现用户输入quit,则退出
            printf("quit\n");
            break;
        }
        read(sock,buf,sizeof(buf));
    }
    close(sock);
    return 0;
}

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值