티스토리 뷰
책) TCP/IP 윈도우 소켓 프로그래밍
간단하게 멀티쓰레드로 send, recv만 해보았습니다.
Create Thread API 정리
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // Security Descriptor
보안설정 옵션, default = null;
SIZE_T dwStackSize, // initial stack size
생성시 요구되는 스택 공간 크기 default = 0;
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
쓰레드가 실행할 함수의 포인터 (원형이 있음)
LPVOID lpParameter, // thread argument
함수의 인자
DWORD dwCreateionFlags, // thread identifier
바로 실행 or 대기 상태 default = 0;
LPDWORD lpThreadId // thread identifier
쓰레드 ID 값 저장
);
//DummyClient
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 50
#define PORTNUM 5000
void err_quit(const char* msg) {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
printf("[%s] %s", msg, (char*)lpMsgBuf);
LocalFree(lpMsgBuf);
}
DWORD WINAPI SendServer(LPVOID arg) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("dlload error\n");
return 1;
}
SOCKET sockfd;
int addrlen;
char buf[MAXLINE];
struct sockaddr_in sockaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET)
{
printf("socket create error\n");
return 1;
}
ZeroMemory(&sockaddr, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(PORTNUM);
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (::connect(sockfd, (SOCKADDR*)&sockaddr, sizeof(sockaddr))) err_quit("Connet");
const char* testdata[] = {
"안녕하세요",
"반가워요",
"오늘따라 할 이야기가 많을 것 같네요.",
"저도 그렇네요"
};
for (int i = 0; i < 4; i++) {
//데이터 입력
int len = strlen(testdata[i]);
strncpy(buf, testdata[i], len);
//데이터 보내기(고정길이)
int retVal = send(sockfd, (char*)&len, sizeof(int), 0);
if (retVal == SOCKET_ERROR) {
err_quit("Send");
break;
}
//데이터 보내기(가변길이)
retVal = send(sockfd, buf, len, 0);
if (retVal == SOCKET_ERROR) {
err_quit("Send");
break;
}
//printf("[TCP 클라이언트] %d바이트를 보냈습니다.\n", retVal);
retVal = recv(sockfd, buf, retVal, 0);
if (retVal == SOCKET_ERROR) {
err_quit("Recv");
break;
}
buf[retVal] = '\0';
printf("입력 받은 데이터 : %s\n", buf);
}
printf("소켓 통신 종료");
closesocket(sockfd);
WSACleanup();
return 0;
}
int main()
{
for (int i = 0; i < 10; i++) {
HANDLE hThread = CreateThread(NULL, 0, SendServer, NULL, 0, NULL);
if (hThread == NULL) return 1;
CloseHandle(hThread);
}
while (1);
return 0;
}
//DummyServer
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 512
#define PORTNUM 5000
void err_quit(const char* msg) {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL);
printf("[%s] %s", msg, (char*)lpMsgBuf);
LocalFree(lpMsgBuf);
}
int recvn(SOCKET s, char* buf, int len, int flag) {
int received;
char* ptr = buf;
int left = len;
while (left > 0) {
received = recv(s, ptr, left, flag);
if (received == SOCKET_ERROR)
return SOCKET_ERROR;
else if (received == 0)
break;
left -= received;
ptr += received;
}
return (len - left);
}
DWORD WINAPI ProcessClient(LPVOID arg) {
SOCKET clientfd = (SOCKET)arg;
SOCKADDR_IN clientaddr;
int addrlen;
int len;
char buf[MAXLINE + 1];
//클라 정보 얻기
addrlen = sizeof(clientaddr);
getpeername(clientfd, (SOCKADDR*)&clientaddr, &addrlen);
while (1) {
//데이터받기(고정길이)
int retVal = recvn(clientfd, (char*)&len, sizeof(int), 0);
if (retVal == SOCKET_ERROR) {
err_quit("Recv");
break;
}
else if (retVal == 0) break;
//데이터받기(가변길이)
retVal = recvn(clientfd, buf, len, 0);
if (retVal == SOCKET_ERROR) {
err_quit("Recv");
break;
}
else if (retVal == 0) break;
//받은 데이터 출력
buf[retVal] = '\0';
printf("[TCP/%s : %d] %s\n", inet_ntoa(clientaddr.sin_addr),
ntohs(clientaddr.sin_port), buf);
retVal = send(clientfd, buf, len, 0);
if (retVal == SOCKET_ERROR) {
err_quit("Send");
break;
}
}
closesocket(clientfd);
printf("[TCP 서버] 클라이언트 종료 : IP 주소 = %s, 포트번호 = %d\n",
inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
return 0;
}
int main()
{
WSADATA wsaData;
SOCKET sockfd, clientfd;
int addrlen;
int len = 0;
WSAEVENT sEvent;
struct sockaddr_in sockaddr,clientaddr;
HANDLE hThread;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("dlload error\n");
return 1;
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET)
{
printf("socket create error\n");
return 1;
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(PORTNUM);
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (::bind(sockfd, (SOCKADDR*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) err_quit("Bind");
if (::listen(sockfd, 5) == SOCKET_ERROR) err_quit("Listen");
while (1)
{
addrlen = sizeof(clientaddr);
clientfd = ::accept(sockfd, (SOCKADDR*)&clientaddr, &addrlen);
if (clientfd == INVALID_SOCKET) {
err_quit("Accept");
break;
}
printf("[TCP서버] 클라이언트 접속 IP : %s %d\n",
inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
hThread = CreateThread(NULL, 0, ProcessClient, (LPVOID)clientfd, 0, NULL);
if (hThread == NULL) closesocket(clientfd);
else CloseHandle(hThread);
}
closesocket(sockfd);
WSACleanup();
return 0;
}
'서버 공부 > 네트워크' 카테고리의 다른 글
GUI 멀티쓰레드 소켓 프로그래밍(TCP) (0) | 2022.07.07 |
---|---|
TCP/IP 윈도우 소켓 프로그래밍 7장 연습문제 (0) | 2022.07.05 |
소켓 네트워크 프로그래밍) 데이터 전송 방식 -> 고정 + 가변 길이 데이터 전송 (0) | 2022.07.04 |
소켓 네트워크 프로그래밍) 데이터 전송 방식 -> 가변 길이 데이터 전송 (0) | 2022.07.04 |
소켓 네트워크 프로그래밍) 세마포어 멀티쓰레드 (0) | 2022.07.02 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 컨퍼런스
- Select모델
- 개발
- 자료구조
- 고양이
- 정보보안
- c++
- 지뢰찾기
- 학교
- STL
- 링크드 리스트
- 야경
- 워셜알고리즘
- Dreamhack
- 백준
- 더블버퍼링
- 보안
- 드림핵
- queue
- 시스템보안
- 인제대학교
- BFS
- 레지스터
- 알고리즘
- 멀티쓰레드
- 스레드풀
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
글 보관함