🧼C, C++/네트워크
다중 스트림서버 C++ TCP #1
개발환경 >> Visual Studio
언어 >> C++17
운영체제 >> Windows10
안녕하세요... 오랜만입니다..!
이번에 시험이 끝나고 쓰는 정식적인 첫 강좌 글이네요.
이번에는 예전부터 쓴다고 예고했던 소켓 다중 스트림 강좌입니다.
다중 스트림이랑 다중 클라이언트와의 차이점은 밑에 그림을 그렸습니다 보시죠~~
우선 저가 이것을 연구하고 싶게 된 계기가
통신을 하면서 데이터를 동시에 보내야 하는데 혼합되지 않도록 할 때가 필요하더라고요
예를 들어서 키로거를 포함한 해킹 툴을 만드는데 키로깅 내용과 다른 작업을 동시에 할 때
데이터가 섞이지 않는 등등.. 이렇게 있기 때문에 연구하기 시작했습니다.
금방 만들 줄 알았는데 2시간 정도 더 걸렸네요...ㅠㅠ
우선 소스코드 보시죠!
[[[ 서버 ]]]
//서버
#pragma comment(lib, "ws2_32.lib")
#define PACKET_SIZE 1024
#include <winsock2.h>
#include <iostream>
#include <thread>
using namespace std;
int cnt = 0, cntport = 4444;
template<typename T> class vec { //자료구조
private:
T* data = NULL;
int size, maxsize;
public:
vec() : size(0), maxsize(1) { }
void add(T t) {
if (size + 1 >= maxsize) {
maxsize *= 2;
T* tmp = new T[maxsize];
for (int i = 0; i < size; i++) tmp[i] = data[i];
tmp[size++] = t;
delete[] data;
data = tmp;
}
else data[size++] = t;
}
int length() { return size; }
T& operator[](const int index) { return data[index]; }
};
class stream { //캡슐화된 하나의 스트림클래스
public:
SOCKET server, _stream;
SOCKADDR_IN addr = { 0 }, client_sock = { 0 };
int client_size, port;
stream() { }
stream(int port) {
this->port = port;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
bind(server, (SOCKADDR*)&addr, sizeof(addr));
listen(server, SOMAXCONN);
client_size = sizeof(client_sock);
_stream = accept(server, (SOCKADDR*)&client_sock, &client_size);
}
}; vec<stream>streams;
void recvs(SOCKET s, int p) { //특정스트림으로부터 값받기
char buffer[PACKET_SIZE];
while (true) {
ZeroMemory(buffer, PACKET_SIZE);
recv(s, buffer, PACKET_SIZE, 0);
if (WSAGetLastError()) break;
cout << p << " ::: " << buffer << endl;
}
}
int main() {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server, _stream;
SOCKADDR_IN addr = { 0 }, client_sock = { 0 };
int client_size;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(server, (SOCKADDR*)&addr, sizeof(addr));
listen(server, SOMAXCONN);
client_size = sizeof(client_sock);
_stream = accept(server, (SOCKADDR*)&client_sock, &client_size);
char msg[PACKET_SIZE];
while (!WSAGetLastError()) {
ZeroMemory(msg, PACKET_SIZE);
cin >> msg;
if (!strcmp(msg, "create")) { //명령어 "create"는 스트림객체 하나를 생성한다.
send(_stream, "Create", PACKET_SIZE, 0);
streams.add(stream(cnt + cntport));
thread(recvs, streams[cnt]._stream, streams[cnt].port).detach();
cnt++;
}
}
closesocket(_stream);
closesocket(server);
for (int i = 0; i < streams.length() - 1; i++) {
closesocket(streams[i]._stream);
closesocket(streams[i].server);
}
WSACleanup();
}
[[[ 클라이언트 ]]]
//클라이언트
#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define PACKET_SIZE 1024
#include <winsock2.h>
#include <iostream>
#include <thread>
using namespace std;
int cnt = 0, cntport = 4444;
template<typename T> class vec { //서버와 설명이 같다.
private:
T* data = NULL;
int size, maxsize;
public:
vec() : size(0), maxsize(1), data(0) { }
void add(T t) {
if (size + 1 >= maxsize) {
maxsize *= 2;
T* tmp = new T[maxsize];
for (int i = 0; i < size; i++) tmp[i] = data[i];
tmp[size++] = t;
delete[] data;
data = tmp;
}
else data[size++] = t;
}
int length() { return size; }
T& operator[](const int index) { return data[index]; }
};
class stream { //캡슐화된 하나의 스트림클래스
public:
SOCKET server;
SOCKADDR_IN addr = { 0 };
int port;
stream() { }
stream(int port) {
this->port = port;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(port);
while (connect(server, (SOCKADDR*)&addr, sizeof(addr)));
cout << port << "연결됨" << endl;
}
}; vec<stream>streams;
void recvs(SOCKET s) { //명령을 받는다
char msg[PACKET_SIZE];
while (true) {
ZeroMemory(msg, PACKET_SIZE);
recv(s, msg, PACKET_SIZE, 0);
if (WSAGetLastError()) return;
if (!strcmp(msg, "Create")) {
streams.add(stream(cnt + cntport));
cnt++;
}
}
}
bool crtPort(int portnum) {
for (int i = 0; i < streams.length(); i++) if (streams[i].port == portnum) return true;
return false;
}
int main() {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server;
SOCKADDR_IN addr = { 0 };
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8080);
while (connect(server, (SOCKADDR*)&addr, sizeof(addr)));
thread(recvs, server).detach();
int portnum;
char buffer[PACKET_SIZE];
while (!WSAGetLastError()) {
ZeroMemory(buffer, PACKET_SIZE);
cin >> portnum >> buffer;
if (crtPort(portnum)) { //만약 존재하는 스트림이라면
send(streams[portnum - cntport].server, buffer, PACKET_SIZE, 0); //메세지전송
}
else cout << "존재하지 않는 스트림입니다." << endl;
}
closesocket(server);
for (int i = 0; i < streams.length()-1; i++) closesocket(streams[i].server);
WSACleanup();
}
[[[ 시연 영상 ]]]
[[[ 다운로드 ]]]
궁금한 부분 있으면 제발 질문 주세요....!!! ㅠㅠㅠ
소스코드는 오늘 낮부터 유동적으로 저가 생각난 대로 쓴 것입니다.
프로젝트 다운로드 링크는 밑에 github링크로 올려놓겠습니다.
감사합니다!!
'🧼C, C++ > 네트워크' 카테고리의 다른 글
소켓 파일전송 프로그램 C++ #4 (6) | 2021.01.21 |
---|---|
소켓 파일전송 C++ #3 (0) | 2021.01.20 |
다중 클라이언트 C++ TCP #3 (수정본) (2) | 2020.12.24 |
소켓 파일전송 C++ #2 (0) | 2020.11.26 |
소켓 커스텀 송수신함수 구현 C++ (0) | 2020.11.26 |
댓글