基于流式套接字的时间同步服务器客户端的设计

本文档详细介绍了如何使用C++和Winsock库在Windows环境下设计一个基于流式套接字的时间同步服务器和客户端。服务器端通过监听特定端口,接收客户端连接请求,发送当前时间信息;客户端则连接服务器并接收时间数据。程序实现了TCP连接的建立、数据传输及关闭。用户无需输入输出,客户端会自动显示服务器返回的时间。
摘要由CSDN通过智能技术生成

实验环境:Dev-C++

1.设计思路

基于流式套接字的时间同步服务器客户端的设计

客户端

1.初始化动态连接库 WSAStartup()
2.设置服务器地址 struct sockaddr_in server_addr;
3.创建套接字 socket()
4.连接服务器 connect()
5.清空缓冲区准备接收数据 meset()
6.while 循环,循环接收数据 recv()
7.关闭套接字 closesocket()
8.释放动态链接库 WSACleanup()

服务器端

1.初始化动态连接库 WSAStartup()
2.设置地址 struct sockaddr_in server_addr;
3.建立监听套接字 sock_listen=socket()
4.监听套接字绑定本地地址 bind()
5.设置监听 listen()
6.while 循环,循环接收客户端请求,返回连接套接字 sock_conn=accept()
7.获取当前时间 time()
8.发送数据 send()
9.关闭连接 shutdown()——>closesocket(sock_conn)
10.WSACleanup()

2.程序

时间程序,循环服务器

//时间服务器 流式套接字 
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <time.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib") //动态链接库
#define MAXLINE 4096//接收缓冲区长度
#define LISTENQ 1024//已完成连接队列以及未完成连接队列之和不可超过 LISTENQ
#define SEVER_PORT 1999//服务器端口号 
int main()
{
	SOCKET sock_conn;//连接套接字 
	char buff[MAXLINE];//缓冲区
	time_t ticks;//time()函数返回值的数据类型是time_t
	int res;//返回值 
	
	//初始化动态链接库
	WORD w_version =MAKEWORD(2,2);
	WSADATA wsa_data;//
	
	res=WSAStartup(w_version,&wsa_data);//成功返回0 
	if(res!=0)
	{
		printf("Error:%d\n",WSAGetLastError());
		printf("WSAStartup Error");
		WSACleanup();
		return -1;
	}
	if(LOBYTE(wsa_data.wVersion)!=2||HIBYTE(wsa_data.wVersion)!=2)//不是需要的版本号
	{
		printf("Version Error:%d",WSAGetLastError());
		WSACleanup();
		return -1;	
	} 
	
	//设置地址(转换为网络字节序) 
	struct sockaddr_in server_addr;//服务器地址结构体 (sockaddr_in IPV4地址结构体)
    memset(&server_addr, 0, sizeof(server_addr));//初始化为0 
    server_addr.sin_family = AF_INET;                // 设地址族为ip协议
    server_addr.sin_addr.s_addr = INADDR_ANY; // INADDR_ANY =0 
    server_addr.sin_port = htons(SEVER_PORT);        //设置端口
	//建立监听套接字
	SOCKET sock_listen; 
	sock_listen=socket(AF_INET, SOCK_STREAM, 0);
    if (sock_listen==INVALID_SOCKET)//socket调用失败返回INVALID_SOCKET 
    {
    	printf("Socket Error:%d",WSAGetLastError());
        WSACleanup();
        return -1;
    }
	//监听套接字绑定本地地址
    res=bind(sock_listen,(struct sockaddr*)&server_addr,sizeof(server_addr));
    if (res == SOCKET_ERROR)
    {
    	printf("Bind Error:%d",WSAGetLastError());
        closesocket(sock_listen);
        WSACleanup();
        return -1;
    }
    //设置监听 最长队列长度LISTENQ
    res=listen(sock_listen,LISTENQ);
    if (res==SOCKET_ERROR)
    {
    	printf("Listen Error:%d",WSAGetLastError());
        closesocket(sock_listen);
        WSACleanup();
        return -1;
    }
    //循环服务器
    while (1)
    {
        //接受客户端连接请求,返回连接套接字sock_conn
        sock_conn=accept(sock_listen,NULL,NULL);
        if (sock_conn==INVALID_SOCKET)
        {
        	printf("Accept Error:%d",WSAGetLastError());
            closesocket(sock_listen);
            WSACleanup();
            return -1;
        }

        //获取当前时间
        ticks=time(NULL);
        time(&ticks);
        memset(buff, 0, sizeof(buff)); //清空缓冲区
        strcpy(buff, ctime(&ticks));   
    //	printf("time:%s",buff);???????
        
        //发送数据
        res=send(sock_conn,buff,(int)strlen(buff), 0);
        if (res==SOCKET_ERROR)
        {
        	printf("Send Error:%d",WSAGetLastError());
            closesocket(sock_conn);
            WSACleanup();
            return -1;
        }
		puts("Sent Time Data Successfully");

        //优雅的关闭连接 
        res=shutdown(sock_conn, SD_SEND);//关闭写通道 
        if (res==SOCKET_ERROR)
        {
        	printf("Shutdown Error:%d", WSAGetLastError());
            closesocket(sock_conn);
            WSACleanup();
            return -1;
        }

        //关闭连接套接字
        closesocket(sock_conn);
        printf("服务器关闭了连接套接字\n");
    }

    // 关闭监听连接
    closesocket(sock_listen);
    puts("服务器关闭了监听套接字"); 
    WSACleanup();
    return 0;
	
	
 } 

时间程序,客户端

//时间客户端
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <time.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib") //动态链接库
#define MAXLINE 4096          //接收缓冲区长度
#define SEVER_PORT 1999      //时间同步服务器端口号
#define server_ip "10.236.239.24" // 服务器ip地址 我主机的IP
int main()
{
	int res;//返回值
	char recv_data[MAXLINE+1]; 
	//初始化动态链接库
	WORD w_version =MAKEWORD(2,2);
	WSADATA wsa_data;
	
	res=WSAStartup(w_version,&wsa_data);//成功返回0 
	if(res!=0)
	{
		printf("Error:%d\n",WSAGetLastError());
		printf("WSAStartup Error");
		WSACleanup();
		return -1;
	}
	if(LOBYTE(wsa_data.wVersion)!=2||HIBYTE(wsa_data.wVersion)!=2)//不是需要的版本号
	{
		printf("Version Error:%d",WSAGetLastError());
		WSACleanup();
		return -1;	
	} 
	
	// 设置服务器地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;                        // ip协议
    server_addr.sin_addr.S_un.S_addr=inet_addr(server_ip); //设置服务器ip
    server_addr.sin_port=htons(SEVER_PORT);                //设置端口

    //创建连接套接字
    SOCKET sock_conn; 
	sock_conn=socket(AF_INET, SOCK_STREAM, 0);
    if(sock_conn==INVALID_SOCKET)
    {
        printf("Socket Error:%d\n", WSAGetLastError());
        WSACleanup();
        return -1;
    }
    // 连接服务器
    res=connect(sock_conn,(struct sockaddr*)&server_addr, sizeof(server_addr));
    if (res==SOCKET_ERROR)
    {
        printf("%d Connect Error!\n", WSAGetLastError());
        closesocket(sock_conn);
        WSACleanup();
        return -1;
    }
    // 清空接收缓冲区 准备接收数据
    memset(recv_data, 0, sizeof(recv_data));

    do
    {
        // 接收数据
        res=recv(sock_conn,recv_data,MAXLINE,0);
        if(res>0)
        {
            printf("%s\n",recv_data);
        }
        else
        {
            if(res==0)
            {
                printf("服务器连接关闭!\n");
            }
            else
            {
                printf("recv error:%d \n", WSAGetLastError());
            }
        }
    } while(res>0);//流式套接字接收到的数据一定大于0 

    // 清理环境 断开连接 释放DLL
    closesocket(sock_conn);
    WSACleanup();
    return 0;
} 

3.用户使用说明(输入 / 输出规定)

时间服务器端以及客户端:
用户都无需输入输出,客户端会自动显示服务器返回的时间,若出错,会显示提示文字并显示WSAGetLastError()返回的错误号。

4.运行结果

在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

20230921

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

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

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

打赏作者

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

抵扣说明:

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

余额充值