当前位置: 首页 > news >正文

Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录

  • Tcp协议
  • Tcp协议常见API接口
    • 1. int socket(int domain, int type, int protocol);
    • 2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
      • struct sockaddr
    • 3. int listen(int socket, int backlog);
    • 4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
    • 5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);
  • telnet通信
  • 服务器代码
    • 1. 单进程版本
    • 2.多进程版本
    • 3.多线程版本
    • 4. 线程池版本(附加字典功能)
      • Main.cc
      • TcpServer.cpp
      • ThreadPool.hpp
      • Task.hpp
      • log.hpp
      • dictionary.hpp
      • dictionary.txt 字典文本(简易)
  • 客户端代码
  • 翻译效果图

Tcp协议

简单了解一下Tcp协议,他与Udp协议都是传输层协议,而他与Udp协议的区别就是Tcp是有连接、可靠传输并且是面向字节流的一种协议。

Tcp协议常见API接口

前两个接口与Udp协议用法一样,只不过将申请套接字的SOCK_DGRAM改为了面向字节流的SOCK_STREAM。

1. int socket(int domain, int type, int protocol);

创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

参数 int domin :指定要在其中创建套接字的通信域。这里我们使用AF_INET采用IPV4通信域。

参数 int type : 指定要创建的套接字类型。 Tcp协议是采用面向字节流,所以是用SOCK_STREAM。

参数 int protocol :指定与套接字一起使用的特定协议。

返回值: 如果成功则返回创建的socket 文件描述符, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAM, 0);if (socket_fd == -1){exit(1);}

2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);

绑定端口号 (TCP/UDP, 服务器)
参数 int socket 就是使用socket接口函数所创建的那个socket文件描述符。

struct sockaddr

在这里插入图片描述
由于底层有不同的网络协议,所以它们的地址格式并不相同,所以通常使用struct sockaddr* 作为参数,然后根据前16位地址类型来确定协议内容。

参数 socklen_t address_len, 结构体sockaddr的长度。
typedef unsigned int socklen_t

返回值: 如果绑定成功则返回0, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAN, 0);if (socket_fd == -1){exit(1);}struct sockaddr_in Server;bzero(&Server, 0);Server.sin_family = AF_INET;Server.sin_addr.s_addr = inet_addr(_ip.c_str()); //?Server.sin_port = htons(_port); //?int n = bind( socket_fd, (const struct sockaddr *)&Server, sizeof(Server));if (n != 0){exit(2);}

3. int listen(int socket, int backlog);

作用:将参数socket套接字用于监听,使其处于listen状态。
参数 backlog 这里暂时不讲,将其设为10左右即可。
返回值:成功则为0,失败则为-1。

代码示例

		int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}

4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);

作用:处于listen状态的网络套接字将持续监听是否有其他网络套接字对本套接字进行链接,该接口函数会阻塞,直到有套接字进行链接,链接成功后将返回一个文件描述符

参数socket:处于listen状态的网络套接字。

参数struct sockaddr *restrict address: 输出型函数,用于保存远端主机的套接字信息。

参数socklen_t *restrict address_len: 输出型参数,用于保存远端主机的套接字的长度。

返回值:成功链接返回一个文件描述符,可对它进行读写操作,失败则返回-1。

5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);

对目标网络套接字发送连接请求,一般适用于客户端去连接服务器。
参数 socket: 本地申请的套接字。
参数const struct sockaddr *address:目标网络套接字的struct sockaddr。
参数socklen_t address_len: 目标网络套接字的struct sockaddr的长度。


telnet通信

telnet是linux中可安装的程序,它是一种基于Tcp协议通信的程序,我们可以使用它来对我们的服务器进行测试。

终端输入该命令

telnet ip[xxx.xxx.xxx.xxx] port[1024+]

如果出现找不到该命令,则是因为你的linux主机没有安装telnet

输入
sudo yum install telnet
安装telnet


使用示例
telnet 127.0.0.1 8888

服务器代码

1. 单进程版本

// version 1 单进程单线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);service(socketfd, client);}}void service(const int socketfd, const struct sockaddr_in client){uint16_t client_port = ntohs(client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信//std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(socketfd, info.c_str(), info.size());}close(socketfd);logMessage(DEBUG, "socketfd: %d closed...", socketfd);}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

该版本缺陷很明显,没办法同时处理多个客户端的数据请求。


2.多进程版本

// version 2 多进程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <wait.h>
const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);int pid = fork();if (pid == 0){if (fork()){// 子进程退出 这样我们的父进程就不需要等service函数执行完才waitpidexit(0);}// 孙子进程close(_listensock);service(socketfd, client);exit(0);}// 父进程close(socketfd);waitpid(pid, nullptr, 0);}}void service(const int socketfd, const struct sockaddr_in client){uint16_t client_port = ntohs(client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信// std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(socketfd, info.c_str(), info.size());}close(socketfd);logMessage(DEBUG, "socketfd: %d closed...", socketfd);}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

缺陷是多进程需要维护的系统资源较多,连接的客户端稍微多点就不行了,简而言之就是多进程占用太大。


3.多线程版本

// version 3 多线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer;class ThreadData
{
public:ThreadData(int fd, struct sockaddr_in client): _socketfd(fd), _client(client){}int _socketfd;struct sockaddr_in _client;
};
class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);ThreadData *td = new ThreadData(socketfd, client);pthread_t tid;pthread_create(&tid, nullptr, service, (void *)td);}}static void *service(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);uint16_t client_port = ntohs(td->_client.sin_port);char ip_buffer[32];inet_ntop(AF_INET, (const void *)&(td->_client.sin_addr), ip_buffer, sizeof(td->_client));std::string cilent_ip = ip_buffer;// 开始接收消息char buffer[1024];while (true){memset(buffer, 0, sizeof buffer);int n = read(td->_socketfd, buffer, sizeof buffer - 1);if (n == 0){logMessage(WARNING, "socketfd[%d] closed...", td->_socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (buffer[n - 1] == '\n'){// 使用telnet通信// std::cout << "发现\\n" << std::endl;buffer[n - 2] = 0;}else{// 使用客户端通信buffer[n] = 0;}std::string info = messageHandle(cilent_ip, client_port, buffer);write(td->_socketfd, info.c_str(), info.size());}delete td;return nullptr;}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

相对多进程版本,系统资源维护成本没那么大,也算一种不错的方案。


4. 线程池版本(附加字典功能)

Main.cc

#include <iostream>
#include "TcpServer.hpp"
#include "threadPool.hpp"
#include "Task.hpp"
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[8888-9000]\n"<< std::endl;
}//多线程版Mainint main(int argc, char* argv[]){if(argc != 2){Usage("./TcpServer");return 1;}int port = atoi(argv[1]);TcpServer ts(port);ts.Init();ts.run();return 0;}

TcpServer.cpp

                 //TcpServer.cpp
// version 4 线程池版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include "threadPool.hpp"
#include "Task.hpp"const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{time_t now = time(nullptr);struct tm *lt = localtime(&now);std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "<< message << std::endl;return message;
}
class TcpServer;class TcpServer
{
public:TcpServer(uint16_t port = default_port, std::string ip = default_ip): _listensock(-1), _server_ip(ip), _server_port(port){}void Init(){// 申请套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1){logMessage(FATAL, "socket create failed...");exit(1);}logMessage(DEBUG, "socket create succeess...");_listensock = sock;// bind套接字struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;inet_aton(_server_ip.c_str(), &local.sin_addr);local.sin_port = htons(_server_port);if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1){logMessage(FATAL, "bind failed..., error:%s", strerror(errno));exit(2);}logMessage(DEBUG, "bind succeess...");// listen beginif (listen(_listensock, backlog) < 0){logMessage(FATAL, "listen failed...");exit(3);}logMessage(DEBUG, "listen succeess...");}void run(){struct sockaddr_in client;socklen_t len;ThreadPool<Task>::GetInstance()->Start();while (true){memset(&client, 0, sizeof client);int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);if (socketfd < 0){logMessage(WARNING, "accept failed...");continue;}logMessage(NORMAL, "accept success..., and get a link, socketfd: %d", socketfd);ThreadPool<Task> *threadpool = ThreadPool<Task>::GetInstance();threadpool->Push(Task(socketfd, client));}}private:int _listensock;std::string _server_ip;uint16_t _server_port;
};

ThreadPool.hpp

#pragma once#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>struct ThreadInfo
{pthread_t tid;std::string name;
};static const int defalutnum = 10;template <class T>
class ThreadPool
{
public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void Wakeup(){pthread_cond_signal(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsQueueEmpty(){return tasks_.empty();}std::string GetThreadName(pthread_t tid){for (const auto &ti : threads_){if (ti.tid == tid)return ti.name;}return "None";}public:static void *HandlerTask(void *args){ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);std::string name = tp->GetThreadName(pthread_self());while (true){tp->Lock();while (tp->IsQueueEmpty()){tp->ThreadSleep();}T t = tp->Pop();tp->Unlock();t();}}void Start(){int num = threads_.size();for (int i = 0; i < num; i++){threads_[i].name = "thread-" + std::to_string(i + 1);pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);}}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Push(const T &t){Lock();tasks_.push(t);Wakeup();Unlock();}static ThreadPool<T> *GetInstance(){if (nullptr == tp_) // ???{pthread_mutex_lock(&lock_);if (nullptr == tp_){// std::cout << "log: singleton create done first!" << std::endl;tp_ = new ThreadPool<T>();}pthread_mutex_unlock(&lock_);}return tp_;}private:ThreadPool(int num = defalutnum) : threads_(num){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~ThreadPool(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);}ThreadPool(const ThreadPool<T> &) = delete;const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:std::vector<ThreadInfo> threads_;std::queue<T> tasks_;pthread_mutex_t mutex_;pthread_cond_t cond_;static ThreadPool<T> *tp_;static pthread_mutex_t lock_;
};template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

Task.hpp

#pragma once
#include <functional>
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "dictionary.hpp"Dictionary dictionary;
class Task
{
public:Task(){}Task(int socketfd, const struct sockaddr_in client): _socketfd(socketfd), _client(client){}void operator()(){char key_word[64];while (true){memset(key_word, 0, sizeof key_word);int n = read(_socketfd, key_word, sizeof key_word - 1);if (n == 0){logMessage(NORMAL, "Connection closed by foreign host, socketfd[%d] closed...", _socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}if (key_word[n - 1] == '\n'){// 使用telnet通信logMessage(DEBUG, "find \\n, telnet connection...");key_word[n - 2] = 0;}else{// 使用客户端通信key_word[n] = 0;}std::string value_word = dictionary.translate(key_word);write(_socketfd, value_word.c_str(), value_word.size());}close(_socketfd);logMessage(DEBUG, "socketfd[%d] closed...", _socketfd);}private:int _socketfd;struct sockaddr_in _client;
};

log.hpp

#pragma once
#include <iostream>
#include <stdarg.h>
#include <string>
#include <time.h>
const char *levels[] = {"NORMAL","WARNING","ERROR","FATAL","DEBUG"};#define NORMAL 0
#define WARNING 1
#define ERROR 2
#define FATAL 3
#define DEBUG 4void logMessage(int level, const char *format, ...)
{
#ifndef debugif (level == DEBUG){return;}
#endifchar stdBuffer[1024];time_t now = time(nullptr);struct tm *lt = localtime(&now);snprintf(stdBuffer, sizeof stdBuffer, "[%s][%d:%d]: ", levels[level], lt->tm_hour, lt->tm_min);char logBuffer[1024];va_list va;va_start(va, format);vsnprintf(logBuffer, sizeof logBuffer, format, va);printf("%s%s\n", stdBuffer, logBuffer);
}

dictionary.hpp

#pragma once
#include <unordered_map>
#include <string>
#include <iostream>
#include <fstream>const char separator = ':';class Dictionary
{
public:Dictionary(){Init();}bool split(const std::string &dword, std::string &part1, std::string &part2){int pos = dword.find(separator, 0);if (pos == std::string::npos){return false;}part1 = dword.substr(0, pos);part2 = dword.substr(pos + 1);}void Init(){std::ifstream in("dictionary.txt");std::string dword;while (std::getline(in, dword)){std::string part1;std::string part2;if (split(dword, part1, part2))_dic[part1] = part2;}in.close();}std::string translate(std::string key){auto it = _dic.find(key);if (it == _dic.end()){return "word unknow";}return it->second;}private:std::unordered_map<std::string, std::string> _dic;
};

dictionary.txt 字典文本(简易)

apple:苹果...
banana:香蕉...
red:红色...
yellow:黄色...
the: 这
be: 是
to: 朝向//对
and: 和
I: 我
in:...里
that: 那个
have: 有
will:for: 为了
but: 但是
as:...一样
what: 什么
so: 因此
he: 他
her: 她
his: 他的
they: 他们
we: 我们
their: 他们的
his: 它的
with:...一起
she: 她
he: 他
it:

客户端代码

客户端代码仅此一套 且可适配服务器四个版本

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
// telnet server_ip server_port
void Usage(const std::string &proc)
{std::cout << "\n\rUsage: " << proc << " ip[xxx.xxx.xxx.xxx] port[8888-9000]\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 3){Usage("./TcpClient");exit(1);}// 申请socketint socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd < 0){logMessage(FATAL, "socket create failed...");exit(2);}// 初始化结构体sockaddrstruct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);if (connect(socketfd, (const sockaddr *)&server, sizeof server) < 0){// connect失败logMessage(FATAL, "connect create failed...");exit(3);}// connect 成功logMessage(DEBUG, "connect create seccess...");// 开始发送和读取数据std::string out_buffer;char in_buffer[1024];while (true){memset(in_buffer, 0, sizeof in_buffer);std::cout << "Send a Message@ ";std::getline(std::cin, out_buffer);write(socketfd, out_buffer.c_str(), out_buffer.size());int n = read(socketfd, in_buffer, sizeof in_buffer - 1);if (n > 0){in_buffer[n] = 0;std::cout << "Server echo Message: " << in_buffer << std::endl;}else if (n == 0){logMessage(WARNING, "Connection closed by foreign host, socketfd[%d] closed...", socketfd);break;}else if (n < 0){logMessage(WARNING, "read erro, socketfd[%d]...");break;}}close(socketfd);return 0;
}

翻译效果图

在这里插入图片描述


相关文章:

Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录 Tcp协议Tcp协议常见API接口1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. int listen(int socket, int backlog);4. int accept(int socket, struct socka…...

实时数据传输:Django 与 MQTT 的完美结合

文章目录 准备工作创建 Django 项目与应用设置 MQTT 服务器编写 Django 视图编写前端模板发布 MQTT 消息运行 Django 项目 在当今互联网应用中&#xff0c;实时数据传输已经成为许多项目的核心需求。无论是社交媒体平台、在线游戏、金融交易还是物联网设备&#xff0c;都需要及…...

创建Django项目及应用

1 创建Project 1个Project可以对应多个app django-admin startproject myproject 2 创建App python manage.py startapp app01 INSTALLED_APPS [# ...app01,app02,# ... ] 如果要让这个应用在项目中起作用&#xff0c;需要在项目的 settings.py 文件的 INSTALLED_APPS 配置…...

Flutter课程分享 -(系统课程 基础 -> 进阶 -> 实战 仿京东商城)

前言 在移动应用开发的世界中&#xff0c;Flutter 作为一款由 Google 推出的开源 UI 软件开发工具包&#xff0c;正迅速赢得开发者们的青睐。其跨平台、高性能、丰富的组件库以及易于学习的特性&#xff0c;使得 Flutter 成为许多开发者的不二选择。然而&#xff0c;对于初学者…...

IDEA 中导入脚手架后该如何处理?

MySQL数据库创建啥的&#xff0c;没啥要说的&#xff01;自行配置即可&#xff01; 1.pom.xml文件&#xff0c;右键&#xff0c;add Maven Project …………&#xff08;将其添加为Maven&#xff09;【下述截图没有add Maven Project 是因为目前已经是Maven了&#xff01;&…...

thinkphp6 queue队列的maxTries自定义

前景需求&#xff1a;在我们用队列的时候发现maxtries的个数时255次&#xff0c;这个太影响其他队列任务 我目前使用的thinkphp版本是6.1 第一部定义一个新的类 CustomDataBase&#xff08;我用的mysql数据库存放的队列&#xff09; 重写__make 和createPlainPayload方法 …...

【PHP项目实战训练】——laravel框架的实战项目中可以做模板的增删查改功能(2)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…...

Kotlin 对象

文章目录 对象表达式&#xff08;匿名对象&#xff09;对象的声明 对象表达式&#xff08;匿名对象&#xff09; 在 Kotlin 中可以使用object {}声明一个匿名的对象&#xff0c;我们无需声明这个对象的类&#xff1a; fun main() {val any object {fun greet() print("…...

力扣 142题 环形链表Ⅱ 记录

题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内…...

乐观锁 or 悲观锁 你怎么选?

你有没有听过这样一句话&#xff1a;悲观者正确&#xff0c;乐观者成功​。那么今天我来分享下什么是乐观锁​和悲观锁。 乐观锁和悲观锁有什么区别&#xff0c;它们什么场景会用 乐观锁 乐观锁基于这样的假设&#xff1a;多个事务在同一时间对同一数据对象进行操作的可能性很…...

《庆余年算法番外篇》:范闲通过最短路径算法在阻止黑骑截杀林相

剧情背景 在《庆余年 2》22集中&#xff0c;林相跟大宝交代完为人处世的人生哲理之后&#xff0c;就要跟大宝告别了 在《庆余年 2》23集中&#xff0c;林相在告老还乡的路上与婉儿和大宝告别后 范闲也在与婉儿的对话中知道黑骑调动是绝密&#xff0c;并把最近一次告老还乡梅…...

大一C语言课设 服装销售系统 代码实现与项目总结

问题分析 服装信息管理及销售管理系统。方便对库存服装的信息管理和添加新服装数据&#xff0c;同时兼具库存数量管理功能。 功能实现 1、建立服装信息库&#xff0c;包括&#xff1a;服装代码、型号、规格、面料、颜色、单价、数量&#xff1b; 2、建立销售信息库&#xff…...

从新手到专家:深入探索JVM垃圾回收--开端篇

引言&#xff1a; 在Java的世界里&#xff0c;垃圾回收&#xff08;Garbage Collection, GC&#xff09;机制扮演着至关重要的角色&#xff0c;它决定了Java应用的性能、稳定性和扩展性。本系列文章旨在深入探讨JVM中的垃圾回收技术&#xff0c;从基础的概念讲起&#xff0c;直…...

R可视化:另类的柱状图

介绍 方格状态的柱状图 加载R包 knitr::opts_chunk$set(echo TRUE, message FALSE, warning FALSE) library(patternplot) library(png) library(ggplot2) library(gridExtra)rm(list ls()) options(stringsAsFactors F)导入数据 data <- read.csv(system.file(&qu…...

Docker的数据管理(数据卷+数据卷容器)

文章目录 一、Docker的数据管理1、概述2、主要的技术&#xff08;三种数据挂载方式&#xff09;2.1、数据卷&#xff08;Volumes&#xff09;2.2、绑定挂载&#xff08;Bind mounts&#xff09;2.3、tmpfs挂载&#xff08;Tmpfs mounts&#xff09;2.4、之间的关系&#xff08;…...

字符串-至多包含K种字符的子串中最长子串(mid)

一、题目描述 二、解题思路 借鉴以下题目思想&#xff0c;使用双指针&#xff0c;外层循环右侧指针移动&#xff0c;内存循环左侧指针移动 字符串-最长不含重复字符的子字符串(mid)-CSDN博客文章浏览阅读622次&#xff0c;点赞17次&#xff0c;收藏4次。java刷题&#xff1a;…...

Docker从安装开始精通

从虚拟机到容器 1.环境配置的难题 软件开发最大的麻烦事之一&#xff0c;就是环境配置。用户计算机的环境都不相同&#xff0c;你怎么知道自家的软件&#xff0c;能在那些机器跑起来&#xff1f; 用户必须保证两件事&#xff1a;操作系统的设置&#xff0c;各种库和组件的安装…...

MFC:初步理解序列化与反序列化(含代码实现)

序列化与反序列化是MFC将对象数据以二进制数据流的形式进行存储和读取的机制&#xff0c;读、写的效率很高。通过序列化与反序列化&#xff0c;可以将程序中对象在内存中数据保存到文件 (磁盘) 或者从文件 (磁盘) 中读取到内存以恢复对象数据&#xff0c;从而实现程序对数据的持…...

python程序控制结构

文章目录 一、python程序控制结构介绍二、顺序结构2.1、print()函数2.2、end参数2.3、input()函数 三、选择结构3.1选择结构的用途 四、循环结构4.1循环结构的构造4.1.1、循环结构的三个要素4.1.2、循环结构的一个要求4.1.3、循环结构的一个关系 4.2、循环语句4.2.1、while语句…...

【GD32】04 - Timer定时器

GD32中的定时器 GD32E230中有七个定时器&#xff0c;六种类型&#xff0c;其中通用的L4版本有两个&#xff0c;其他类型的各一个。 那我们就以通用L4这个类型来敲代码&#xff0c;其他流程是通用的。 通用L4 虽然每种类型的定时器都有自己的结构框图&#xff0c;但是其实大差…...

Golang | Leetcode Golang题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {buy1, sell1 : -prices[0], 0buy2, sell2 : -prices[0], 0for i : 1; i < len(prices); i {buy1 max(buy1, -prices[i])sell1 max(sell1, buy1prices[i])buy2 max(buy2, sell1-prices[i])sell2 m…...

Leetcode2028. 找出缺失的观测数据

Every day a Leetcode 题目来源&#xff1a;2028. 找出缺失的观测数据 解法1&#xff1a;模拟 统计当前 m 个元素的总和 curSum sum(rolls)&#xff0c;总共 mn 个元素和为 total (m n) * mean。 排除 2 种情况&#xff1a; total - curSum > 6 * n&#xff1a;n 个…...

如何在CentOS中合理划分磁盘空间以优化系统性能

目录 前言 理想的分区方案 为什么需要单独分区 安全性 性能 管理和维护 稳定性和可靠性 升级和兼容性 结论 前言 在进行CentOS系统的安装和配置时&#xff0c;合理划分磁盘空间是确保系统性能、安全性和易于管理的关键步骤。本文将探讨如何根据系统的硬件配置和预期用途…...

算法(十一)贪婪算法

文章目录 算法简介算法概念算法举例 经典问题 -背包问题 算法简介 算法概念 贪婪算法&#xff08;Greedy&#xff09;是一种在每一步都采取当前状态下最好的或者最优的选择&#xff0c;从而希望导致结果也是全局最好或者最优的算法。贪婪算法是当下局部的最优判断&#xff0c…...

Rust之函数式语言特性:迭代器和闭包(一):概述

开发环境 Windows 11Rust 1.78.0 VS Code 1.89.1 项目工程 这次创建了新的工程minigrep. 函数式语言特性:迭代器和闭包 Rust的设计从许多现有语言和技术中获得了灵感&#xff0c;其中一个重要影响是函数式编程。函数式编程通常包括通过在参数中传递函数、从其他函数返回函数、…...

配置资源管理

一 Secret Secret 是用来保存密码、token、密钥等敏感数据的 k8s 资源&#xff0c;这类数据虽然也可以存放在 Pod 或者镜像中&#xff0c;但是放在 Secret 中是为了更方便的控制如何使用数据&#xff0c;并减少暴露的风险。 1 有三种类型&#xff1a; kubernetes.io/service…...

unity2020打包webGL时卡进程问题

我使用的2020.3.0f1c1&#xff0c;打包发布WEB版的时候会一直卡到asm2wasm.exe这个进程里&#xff0c;而且CPU占用率90%以上。 即使是打包一个新建项目的空场景也是同样的问题&#xff0c;我尝试过一直卡在这里会如何&#xff0c;结果还真打包成功了。只是打包一个空场景需要20…...

云原生架构相关技术_3.无服务器技术

1.技术特点 1.1面向特定领域的后端云服务&#xff08;BaaS&#xff09; 随着以Kubernetes为代表的云原生技术成为云计算的容器界面&#xff0c;Kubernetes成为云计算的新一代操作系统。面向特定领域的后端云服务&#xff08;BaaS&#xff09;则是这个操作系统上的服务API&…...

Leetcode:Z 字形变换

题目链接&#xff1a;6. Z 字形变换 - 力扣&#xff08;LeetCode&#xff09; 普通版本&#xff08;二维矩阵的直接读写&#xff09; 解决办法&#xff1a;直接依据题目要求新建并填写一个二维数组&#xff0c;最后再将该二维数组中的有效字符按从左到右、从上到下的顺序读取并…...

Python 3 判断文件是否存在

1 使用os.path模块 import osfile_path hello.txtif os.path.exists(file_path):print(f"文件 {file_path} 存在。") else:print(f"文件 {file_path} 不存在。") 2 使用pathlib模块 from pathlib import Pathfile_path Path(word.txt)if file_path.ex…...

(深度学习记录)第TR3周:Transformer 算法详解

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文本的输入处理中&#xff0c;transformer会将输入文本序列的每个词转化为一个词向量&#xff0c;我们通常会选择一个合适的长度作为输入…...

谷神前端组件增强:自定义列

初始化 $gp.customColumn {}initColumnPool /*** initColumnPool* 初始化列池* * param prefix 前缀* param length 长度* * return Array 列ID数组* */ function initColumnPool (prefix, length) {return Array.from({length}, (value, index) > prefix index) } self…...

31-ESP32-S3-WIFI篇-02 Event Group (事件标记组)

ESP32-S3-WIFI 事件标记组 介绍 在ESP32-S3的WiFi驱动程序中&#xff0c;事件标记组&#xff08;Event Group&#xff09;是一个非常重要的概念。它是FreeRTOS中的一种同步机制&#xff0c;用于在任务之间传递和同步事件。在WiFi驱动程序中&#xff0c;我们使用事件标记组来通…...

构建企业级AI私有知识库

一、引言 在当今竞争激烈的市场环境中&#xff0c;企业为了保持竞争优势&#xff0c;需要高效地管理和利用内部知识资源。构建一个企业级AI私有知识库&#xff0c;不仅可以集中存储和管理企业知识&#xff0c;还能通过人工智能技术实现知识的智能化处理和利用。本文将详细介绍…...

C语言王国——杨氏矩阵

目录 1. 引言 2. 了解杨氏矩阵 3. 思路分析 4. 代码 5. 总结 1. 引言 最近在做二维数组的训练的时候发现了一个很有意思的题&#xff1a; 一看这不是杨氏矩阵嘛&#xff0c;接下来就由姜糖我带大家了解一下这个著名的矩阵。 2. 了解杨氏矩阵 通过查阅百度得知&#xff1a; …...

陪玩小程序都需要怎么做?

开发陪玩小程序需要进行全面的需求分析、功能规划、技术选型、界面设计等一系列步骤。陪玩小程序作为一种新兴的网络服务平台&#xff0c;为用户提供了寻找游戏伙伴、预约陪玩服务等功能&#xff0c;满足了用户在游戏领域的社交互动和技能提升需求。具体分析如下&#xff1a; 需…...

postgressql——子事务可见性判断 性能问题(8)

子事务可见性判断 & 性能 测试SQL BEGIN; PREPARE sel(integer) ASSELECT count(*)FROM contendWHERE id BETWEEN $1 AND $1 + 100; PREPARE upd(integer) ASUPDATE contend SET val = val + 1WHERE id IN ($1, $1 + 10, $1 + 20, $1 + 30);SAVEPOINT a; \set rnd random…...

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试USB摄像头

20240531在飞凌的OK3588-C开发板上跑原厂的Buildroot测试USB摄像头 2024/5/31 20:04 USB摄像头分辨率&#xff1a;1080p&#xff08;1920x1080&#xff09; 默认编译Buildroot的SDK即可点亮USB摄像头。v4l2-ctl --list-devices v4l2-ctl --list-formats-ext -d /dev/video74 …...

从0开始学统计-什么是回归?

1.什么是回归&#xff1f; 回归&#xff08;Regression&#xff09;是统计学中一种用于探索变量之间关系的分析方法。它主要用于预测一个或多个自变量&#xff08;输入变量&#xff09;与因变量&#xff08;输出变量&#xff09;之间的关系。在回归分析中&#xff0c;我们尝试根…...

Element-ui使用上传时弹框选择文件类型

实现效果 1&#xff0c;点击上传&#xff0c;上传文件&#xff1b; 2&#xff0c;选择文件&#xff1b; 3&#xff0c;弹框选择文件类型&#xff1b; 4&#xff0c;选择类型后确定上传&#xff1b; 一&#xff0c;上传 跳过&#xff1b; 二&#xff0c;定义弹框下拉框…...

原生小程序一键获取手机号

1.效果图 2.代码index.wxml <!-- 获取手机号 利用手机号快速填写的功能&#xff0c;将button组件 open-type 的值设置为 getPhoneNumber--><button open-type"getPhoneNumber" bindgetphonenumber"getPhoneNumber">获取手机号</button> …...

ARM虚拟机安装OMV

OMV(OpenMediaVault)是基于 Debian GNU/Linux 的网络连接存储&#xff08;network attached storage&#xff0c;NAS&#xff09;解决方案。它包含 SSH、(S) FTP、SMB/CIFS、DAAP 媒体服务器、rsync、 BitTorrent 等很多种服务。它可用于 x86-64 和 ARM 平台。 在x86-64平台上&…...

【协议开发系列】梳理关于TCP和UDP两种协议的区别和使用场景

起源 前二天项目上在核对外部对接服务的五元组列表的时候&#xff0c;有一位客户提问对于同样的服务同时支持tcp和udp二种方式&#xff0c;有什么优点和缺点&#xff0c;应该如何选择&#xff1f;这个问题突然让我愣了一下&#xff0c;确实好久没有“温故”了&#xff0c;相关…...

vue blob实现自定义多sheet数据导出到excel文件

背景&#xff1a;最近vue项目遇到一个需求&#xff0c;就是需要将多个表格分成不同sheet页并导出&#xff0c;之前的工具类只能导出一个sheet页&#xff0c;所以在原有的基础上&#xff0c;调整一下&#xff0c;让它支持多sheet导出。 vue blob文件流&#xff0c;这个肯定要的…...

Python—面向对象小解(3)

一、多态 多态指的是一类事物的多中形态 相同的方法&#xff0c;产生不同的执行结果 运算符 * 的多态 int int 加法计算 str str 字符串拼接 list list 列表的数据合并 在python中可以使用类实现一个多态效果 在python中使用重写的方式实现多态 &#xff08;1&#xff09;定…...

Nginx超时时间

Nginx是一款自由、开源、高性能的HTTP和反向代理服务器&#xff0c;它可以通过不同的设置来提高网站的性能和安全性。其中&#xff0c;设置Nginx超时时间非常重要&#xff0c;因为它将直接影响网站的响应速度和用户体验。本文将从多个方面详细阐述Nginx超时时间的设置方法与注意…...

Imgs,GT,Edge,Gradient_all,Gradient_Foreground

保存一下&#xff1a; 做个记录&#xff1a; import cv2 import os import numpy as np# 对整张图片做canny检测 得到纹理图 def canny_all(input_path, output_path):# 遍历文件夹中的所有文件for filename in os.listdir(input_path):# 构造完整的文件路径image_path os.p…...

自学成才Flutter 弹性布局、线性布局

本文我们要介绍 Flutter 中布局 Widget&#xff0c;包括弹性布局、线性布局 流式布局和层叠布局。 Flutter中文网 Flutter开发 一、弹性布局--Flex Flex 类似 Android 中的 FlexboxLayout&#xff0c;和 Expanded 配合使用可以实现子Widget 按照一定比例来分配父容器空间。 使…...

Part 3.1 深度优先搜索

深度优先搜索&#xff08;DFS&#xff09;&#xff0c;即按照深度优先的顺序搜索的算法。 深度优先搜索一般使用栈来实现。 [USACO1.5] 八皇后 Checker Challenge 题目描述 一个如下的 6 6 6 \times 6 66 的跳棋棋盘&#xff0c;有六个棋子被放置在棋盘上&#xff0c;使得…...

前端Vue小兔鲜儿电商项目实战Day03

一、Home - 整体结构搭建和分类实现 1. 页面结构 ①按照结构新增5个组件&#xff0c;准备最简单的模板&#xff0c;分别在Home模块的入口组件中引入 src/views/Home/components/ HomeCategory.vue HomeBanner.vue HomeNew.vue HomeHot.vue HomeProduct.vue <script …...