返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Windows下VScode实现简单回声服务的方法
  • 126
分享到

Windows下VScode实现简单回声服务的方法

2024-04-02 19:04:59 126人浏览 独家记忆
摘要

目录1. 相关知识1.1 什么是回声服务1.2 服务端、客户端如何交互2. Socket 编程2.1 服务端2.2 客户端3. demo展示3.1 服务端源代码3.2 客户端源代码3

1. 相关知识

1.1 什么是回声服务

回声服务端可以将客户端传来的信息,再原封不动地发送给客户端,因而得名 epoch 服务。服务端 server 和 客户端 client 基于 tcp 进行通信。

1.2 服务端、客户端如何交互

下图给出了基于 TCP 的服务器端和客户端的交互过程。
首先服务端创建 socket 套接字,之后调用 bind 函数分配服务端 socket 地址,调用 listen 函数使服务端进入监听状态,同时维护一个半连接队列。服务端之后会调用 accept 函数,进入阻塞状态。accept 函数会从全连接的队列中取出一个连接进行处理。TCP 连接建立完成之后,服务端和客户端即可通过 send 和 recv 发送和接收数据。
注意:服务端调用 listen 函数进入等待连接状态后,客户端才能调用 connect 函数发起连接请求。

在这里插入图片描述

服务端和客户端交互就是一种通信过程,它们基于 TCP 实现 socket 通信。TCP 协议中有三次握手、四次挥手的协议内容,如下图所示。

在这里插入图片描述

服务端和客户端通过三次握手建立连接,四次挥手断开连接。
具体到socket编程实现,则是通过 listen 和 connect 函数实现 TCP 连接的建立,通过 close 函数关闭 socket 套接字,实现TCP连接的断开。

2. socket 编程

下面分别介绍客户端和服务端的常用函数和具体实现过程。

2.1 服务端

服务端的实现过程如下图所示。

在这里插入图片描述

下面给出实现基于TCP的服务端的常用函数。

1.首先需要对 Winsock 套接字库进行初始化,调用 WSAStartup 函数。
下面给出 WSAStartup 函数调用的基本格式,一般只需调用即可,无需了解参数含义。


#include <winsock2.h>
int main(int arGC, char* argv[])
{
	WSADATA wsaData;
	if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
	ErrorHandling("WSAStartup() error!"); 
	return 0;
}

成功时返回 0 ,失败返回非零的错误代码值

2.创建 socket 套接字


SOCKET socket(int af, int type, int protocol);

成功时返回套接字句柄,失败返回 INVALID_SOCKET

3.调用 bind 函数,为套接字分配 IP 地址和端口号


int bind(SOCKET s, const struct sockaddr * name, int namelen);

成功时返回 0,失败返回 SOCKET_ERROR

4.调用 listen 函数,监听客户端连接


int listen(SOCKET s, int backlog);

成功时返回 0 ,失败返回 SOCKET_ERROR

5.调用 accept 函数,允许客户端连接


SOCKET accept(SOCKET s, struct sockaddr * addr, int * addrlen);

成功时返回套接字句柄,失败返回 INVALID_SOCKET

6.调用 send 函数, 给连接的客户端发送数据


int send(SOCKET s, const char * buf, int len, int flags):

成功时返回传输字节数,失败返回 SOCKET_ERROR

7.调用 recv 函数,接收连接的客户端发来的数据


int recv(SOCKET s, const char * buf, int len, int flags);

成功时返回接收字节数,失败返回 SOCKET_ERROR

8.调用 close 函数,关闭套接字。


int closesocket(SOCKET s);

成功时返回 0 ,失败时返回 SOCKET_ERROR

9.注销 Winsock 相关库


int WSACleanup(void);

成功时返回 0 ,失败时返回 SOCKET_ERROR

2.2 客户端

客户端的实现过程如下图所示。

在这里插入图片描述

下面给出实现基于TCP的客户端的常用函数。

1.创建 socket 套接字


SOCKET socket(int af, int type, int protocol);

成功时返回套接字句柄,失败返回 INVALID_SOCKET

2.调用connect函数,发起连接请求


int connect(SOCKET s, const struct sockaddr * name, int namelen);

成功时返回 0,失败返回 SOCKET_ERROR

3.调用 send 函数, 给连接的服务端发送数据


int send(SOCKET s, const char * buf, int len, int flags):

成功时返回传输字节数,失败返回 SOCKET_ERROR

4.调用 recv 函数,接收连接的服务端发来的数据


int recv(SOCKET s, const char * buf, int len, int flags);

成功时返回接收字节数,失败返回 SOCKET_ERROR

5.调用 close 函数,断开连接。


int closesocket(SOCKET s);

成功时返回 0 ,失败时返回 SOCKET_ERROR

3. demo展示

3.1 服务端源代码

回声服务端的c++代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 1024

void ErrorHandling(char *message);

int main(int argc, char *argv[])
{
  WSADATA wsaData;
  SOCKET hServSock, hClntSock;
  char message[BUF_SIZE];
  int strLen, i;

  SOCKADDR_IN servAdr, clntAdr;
  int clntAdrSize;

  if (argc != 2)
  {
    printf("Usage : %s <port>\n", argv[0]);
    exit(1);
  }

  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    ErrorHandling("WSAStartup() error!");

  hServSock = socket(PF_INET, SOCK_STREAM, 0);
  if (hServSock == INVALID_SOCKET)
    ErrorHandling("socket() error");

  memset(&servAdr, 0, sizeof(servAdr));
  servAdr.sin_family = AF_INET;
  
  servAdr.sin_addr.s_addr = inet_addr("127.0.0.1");
  servAdr.sin_port = htons(atoi(argv[1]));

  if (bind(hServSock, (SOCKADDR *)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
    ErrorHandling("bind() error");

  if (listen(hServSock, 5) == SOCKET_ERROR)
    ErrorHandling("listen() error");

  clntAdrSize = sizeof(clntAdr);

  for (i = 0; i < 5; i++)
  {
    hClntSock = accept(hServSock, (SOCKADDR *)&clntAdr, &clntAdrSize);
    if (hClntSock == -1)
      ErrorHandling("accept() error");
    else
      printf("Connected client %d \n", i + 1);

    while ((strLen = recv(hClntSock, message, BUF_SIZE, 0)) != 0)
      send(hClntSock, message, strLen, 0);

    closesocket(hClntSock);
  }

  closesocket(hServSock);
  printf("game over");
  WSACleanup();
  return 0;
}

void ErrorHandling(char *message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

注意:运行服务端代码时,须加入命令行参数(端口号)。如代码所示, IP 地址已经绑定 127.0.0.1。配置 tasks.JSON 如下所示。


{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "C/C++: g++.exe build active file",
      "command": "E:\\mingw64\\bin\\g++.exe",
      "args": [
        "-g",
        "${file}",
        "-lws2_32",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe"
      ],
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": ["$gcc"],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

配置信息 launch.json 如下 。


{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more infORMation, visit: https://Go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) 启动",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/${fileBasenameNoExtension}.exe",
      "args": ["9190"],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "E:\\mingw64\\bin\\gdb.exe",
      "setupCommands": [
        {
          "description": "为 gdb 启用整齐打印",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ]
    }
  ]
}

3.2 客户端源代码

回声客户端的C++代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 1024

void ErrorHandling(char *message);

int main(int argc, char *argv[])
{
  WSADATA wsaData;
  SOCKET hSocket;
  char message[BUF_SIZE];
  int strLen;
  SOCKADDR_IN servAdr;

  if (argc != 3)
  {
    printf("Usage : %s <IP> <port>\n", argv[0]);
    exit(1);
  }

  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    ErrorHandling("WSAStartup() error!");

  hSocket = socket(PF_INET, SOCK_STREAM, 0);
  if (hSocket == INVALID_SOCKET)
    ErrorHandling("socket() error");
  printf("%s\n", argv[0]);
  printf("%s\n", argv[1]);
  printf("%s\n", argv[2]);
  memset(&servAdr, 0, sizeof(servAdr));
  servAdr.sin_family = AF_INET;
  servAdr.sin_addr.s_addr = inet_addr(argv[1]);
  servAdr.sin_port = htons(atoi(argv[2]));
  if (connect(hSocket, (SOCKADDR *)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
    ErrorHandling("connect() error!");
  else
    puts("Connected...........");

  while (1)
  {
    fputs("Input message(Q to quit): ", stdout);
    fgets(message, BUF_SIZE, stdin);

    if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
      break;

    send(hSocket, message, strlen(message), 0);
    strLen = recv(hSocket, message, BUF_SIZE - 1, 0);
    printf("Message from server: %s", message);
  }

  closesocket(hSocket);
  WSACleanup();
  return 0;
}

void ErrorHandling(char *message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

同样,客户端也需要加入命令行参数 127.0.0.1 9190运行。可以通过修改配置文件生成客户端。
也可以通过cmd或者终端生成客户端。cmd 方式如下:
首先通过 g++ 编译器对 client.cpp 文件进行编译生成 .exe 文件。
之后在终端中,输入 client.exe 127.0.0.1 9190 即可创建客户端。

3.3 运行结果

服务端可以服务 5 个客户端,即 accept 队列长度为 5。
客户端的运行结果如下,前5个客户端均与服务端连接成功,可以收到“回声”。第6次连接时,由于服务端断开连接,所以产生连接错误。

在这里插入图片描述
在这里插入图片描述

服务端的运行结果如下图所示。服务端可以连接5个客户端,之后服务端将断开连接。并显示 “game over”。

在这里插入图片描述

参考链接

深入理解TCP协议与UDP协议的原理及区别

vscode官方文档

到此这篇关于windows下VScode实现简单回声服务的文章就介绍到这了,更多相关VScode回声服务内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Windows下VScode实现简单回声服务的方法

本文链接: https://lsjlt.com/news/132561.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Windows下VScode实现简单回声服务的方法
    目录1. 相关知识1.1 什么是回声服务1.2 服务端、客户端如何交互2. socket 编程2.1 服务端2.2 客户端3. demo展示3.1 服务端源代码3.2 客户端源代码3...
    99+
    2024-04-02
  • C语言实现简单回声服务器
    本文实例为大家分享了C语言实现简单的回声服务器,供大家参考,具体内容如下 新建echo_server.c #include<stdio.h> #include <u...
    99+
    2024-04-02
  • Android简单实现屏幕下方Tab菜单的方法
    本文实例讲述了Android简单实现屏幕下方Tab菜单的方法。分享给大家供大家参考,具体如下: 看到很多热门的Android程序(如:新浪微博、腾讯微博、京东商城、淘宝、当当等...
    99+
    2022-06-06
    方法 tab Android
  • Python技法之简单递归下降Parser的实现方法
    目录1. 算术运算表达式求值2. 生成表达式树左递归和运算符优先级陷阱3. 相关包参考总结1. 算术运算表达式求值 在上一篇博文《Python技法:用re模块实现简易tokenize...
    99+
    2024-04-02
  • MySQL实现单表查询的简单方法
    本文主要给大家简单讲讲MySQL实现单表查询的简单方法,相关专业术语大家可以上网查查或者找一些相关书籍补充一下,这里就不涉猎了,我们就直奔主题吧,希望MySQL实现单表查询的简单方法这篇文章可以给大家带来一...
    99+
    2024-04-02
  • PHP实现简单爬虫的方法
    PHP实现简单爬虫的方法,php实现爬虫 本文实例讲述了PHP实现简单爬虫的方法。分享给大家供大家参考。具体如下: ...
    99+
    2023-09-08
    php 爬虫 开发语言
  • python排序算法的简单实现方法
    1 冒泡排序  1.1 算法步骤: 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元...
    99+
    2024-04-02
  • Python实现emoji表情的简单方法
    前言 作为一个数据分析师,应该信奉一句话——“一图胜千言”。不过这里要说的并不是数据可视化,而是一款全民向的产品形态——表情包!!!! 表情包不仅仅是一种符号,更是一种文化——是促进社交乃至社会发展的动力之一,就像懒...
    99+
    2022-06-02
    python emoji表情存储 python表情包 python emoji
  • Python实现简单字典树的方法
    本文实例讲述了Python实现简单字典树的方法。分享给大家供大家参考,具体如下: #coding=utf8 """代码实现了最简单的字典树,只支持由小写字母组成的字符串。 在此代码基础上扩展一下,就可以...
    99+
    2022-06-04
    字典 简单 方法
  • Python简单实现enum功能的方法
    本文实例讲述了Python简单实现enum功能的方法。分享给大家供大家参考,具体如下: class Enumerate(object): def __init__(self,names): ...
    99+
    2022-06-04
    简单 功能 方法
  • python实现简单socket通信的方法
    本文实例讲述了python实现简单socket通信的方法。分享给大家供大家参考,具体如下: 刚刚开始接触python,实现了一个helloworld程序---关于udp协议的socket通信demo。 首先...
    99+
    2022-06-04
    通信 简单 方法
  • Android实现简单MD5加密的方法
    本文实例讲述了Android实现简单MD5加密的方法。分享给大家供大家参考,具体如下: 网上关于android下MD5加密的资料很多,但是测试了下总是跟网站的md5加密不一样,...
    99+
    2022-06-06
    加密 方法 md5加密 Android
  • Python实现简单的多任务mysql转xml的方法
    本文实例讲述了Python实现简单的多任务mysql转xml的方法。分享给大家供大家参考,具体如下: 为了需求导出的格式尽量和navicat导出的xml一致。 用的gevent,文件i/o操作会阻塞,所以并...
    99+
    2022-06-04
    简单 方法 Python
  • Android实现悬浮窗的简单方法实例
    目录1. 前言2.原理3.具体实现3.1浮窗布局3.2 悬浮窗的实现1. 使用服务Service2. 获取WindowManager并设置LayoutParams3. 创建View并...
    99+
    2024-04-02
  • Android简单实现启动画面的方法
    本文实例讲述了Android简单实现启动画面的方法。分享给大家供大家参考,具体如下: 核心代码: package com.demo.app; import android.a...
    99+
    2022-06-06
    方法 启动 动画 Android
  • Android实现简单图片压缩的方法
    本文实例讲述了Android实现简单图片压缩的方法。分享给大家供大家参考,具体如下: 在开发图片浏览器等软件是,很多时候要显示图片的缩略图,而一般情况下,我们要将图片按照固定大...
    99+
    2022-06-06
    压缩 方法 图片 图片压缩 Android
  • 实现MySQL更新查询的简单方法
    下文主要给大家带来实现MySQL更新查询的简单方法,希望这些内容能够带给大家实际用处,这也是我编辑实现MySQL更新查询的简单方法这篇文章的主要目的。好了,废话不多说,大家直接看下文吧。  &nb...
    99+
    2024-04-02
  • 关于Promise基本方法的简单实现
    目录前言catch() 方法done() 方法finally() 方法Promise.all() 方法Promise.race() 方法Promise.resolve() 和 Pro...
    99+
    2024-04-02
  • Unity实现简单换装系统的方法
    小编给大家分享一下Unity实现简单换装系统的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!代码如下:using UnityEngine;using...
    99+
    2023-06-14
  • CSS3中@keyframes简单动画的实现方法
    这篇文章主要介绍了CSS3中@keyframes简单动画的实现方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。CSS3 @keyframes简单动画实现定义:通过 @key...
    99+
    2023-06-08
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作