|
Flags |
Meaning |
WSA_FLAG_OVERLAPPED |
오버랩 소켓을 생성. I/O 오퍼레이션을 위하여 WSASend, WSASendTo, WSARecv, WSARecvFrom, WSAIoctl 함수를 사용할 수 있다. NULL로 지정하면 넌 – 오버랩 소켓으로 사용 |
WSA_FLAG_MULTIPOINT_C_ROOT |
생성된 소켓이 멀티 포인트 세션에서 c_root가 될 것이라고 알려주는 플래그 |
WSA_FLAG_MULTIPOINT_C_LEAF |
생성된 소켓이 멀티 캐스트 세션에서 c_leaf가 될 것이라고 알려주는 플래그 |
WSA_FLAG_MULTIPOINT_D_ROOT |
생성된 소켓이 멀티 포인트 세션에서 d_root가 될 것이라고 알려주는 플래그 |
WSA_FLAG_MULTIPOINT_D_LEAF |
생성된 소켓이 멀티 포인트 세션에서 d_leaf가 될 것이라고 알려주는 플래그 |
5. WSASend
: 연결과정은 일반소켓의 연결과정과 차이가 없으나, 데이터의 입출력에 사용하는 함수는 달리해야 한다.
int WSASend(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfByteSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE
lpCompletionRoutine
);
s → 해당 소켓
lpBuffers → WSABUF 구조체 배열을 가리키는 포인터
dwBufferCount → lpBuffers가 가리키는 WSABUF 구조체 배열의 크기
lpNumberOfByte → 전송된 바이트 수
dwFlags → 데이터 전송 방식의 옵션
lpOverlapped → WSAOVERLAPPED 구조체 변수의 포인터
lpCompletionRoutine → Completion Routine의 포인터 전달
Flags |
Meaning |
MSG_DONTROUTE |
데이터를 라우팅 하지 않도록 명시 윈도우 소켓 서비스 프로바이더는 이 플래그를 무시할 수 있습니다. |
MSG_OOB |
SOCK_STREAM으로 생성한 연결지향형 소켓에서 out-of-band 데이터를 전송할 때 사용하는 값 |
MSG_PARTIAL |
lpBuffers 매개변수가 부분적인 메시지만을 담도록 명시. 부분적인 메시지를 지원하지 않을 경우 WSAEOPNOTSUPP 에러코드를 반환 |
5.1 WSABUF 구조체
typedef struct __WSABUF
{
u_long len; // 전송할 데이터의 크기
char FAR* buf; // 버퍼의 주소 값
}WSABUF, *LPWSABUF;
6. WSAOVERLAPPED 구조체
typedef struct _WSAOVERLAPPED{
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
}WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;
Internal, InternalHigh, Offset, OffsetHigh : 시스템 내부에서 지정해주기 때문에 직접 수정하지 말아야
한다. hEvent : 이벤트 오브젝트를 등록하는데 사용한다.
7. Completion Routine
: I/O가 완료되었을 때, 자동으로 호출될 함수 (WSASend, WSARecv함수의 마지막 전달인자)
void CallBack CompletionRoutine(
DWORD dwError,
DWORD cbTransfered,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags
);
dwError → 오류정보 전달
cbTransfered → 전송된 바이트 수가 전달된다.
lpOverlapped → WSARecv 함수 호출 시 전달한 구조체 변수
dwFlags → 옵션
8. WSARecv
: WSASend 함수와 인자들이 같은 lpFlags만 레퍼런스 참조형으로 변경하면 된다.
Int WSARecv(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfByteSent,
DWORD lwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE
lpCompletionRoutine
);
9. 예제 코드 분석
[OverlappedCl.cpp]
#pragma comment(lib,"ws2_32")
#include <winsock2.h>
#include <stdio.h>
#include <conio.h>
#define FNLEN 200
DWORD WINAPI Doit(LPVOID pin);
void main()
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2,2),&wsadata);
DWORD ThreadID;
int i=0;
for(i=0;i<4;i++) // 4명이라고 가정하고
{
CloseHandle(CreateThread(0,0,Doit,(LPVOID) (i+1),0,&ThreadID));
}
getch();
WSACleanup();
}
DWORD WINAPI Doit(LPVOID pin)
{
SOCKET sock;
sock = socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN servaddr={0,};
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.34.91");
servaddr.sin_port = htons(11800);
int re = connect(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
int a=(int )pin;
char fname[256];
sprintf(fname,"%d.zip",a);
if(re == 0)
{
printf("%d접속성공\n",a);
}
WIN32_FIND_DATA wfd;
FindClose(FindFirstFile(fname,&wfd));
char buf[1000];
memset(buf,0,sizeof(buf));
strcpy(buf,fname);
*((int *)(buf+FNLEN)) = wfd.dwFileAttributes;
*((int *)(buf+FNLEN + sizeof(int))) = wfd.nFileSizeLow;
send(sock,buf,1000,0);
HANDLE hFile;
DWORD dwRead;
hFile = CreateFile(fname,GENERIC_READ,0,0,OPEN_EXISTING,wfd.dwFileAttributes,0);
while(wfd.nFileSizeLow>1000)
{
ReadFile(hFile,buf,1000,&dwRead,0);
send(sock,buf,1000,0);
wfd.nFileSizeLow -= 1000;
}
if(wfd.nFileSizeLow)
{
ReadFile(hFile,buf,wfd.nFileSizeLow,&dwRead,0);
send(sock,buf,wfd.nFileSizeLow,0);
}
CloseHandle(hFile);
closesocket(sock);
printf("%d전송성공\n",a);
return 0;
}
-----------------------------------------------------------------------------------------------------------
[Overlapped.cpp]
#pragma comment(lib,"ws2_32")
#include <winsock2.h>
#include <stdio.h>
SOCKET sock;
DWORD rcnt;
#define FNLEN 200
void CALLBACK ComRoutine(
DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags
);
int pcnt=0; //테스트카운트를위한정수형변수
// 사용하게될구조체를WSAOVERLAPPED구조체를이용해서정의
{
//overlapped(중첩) 입출력연산의 초기화와 이후 작업완료
WSAOVERLAPPED ol; //루틴사이에서의통신수단을제공한다.
SOCKET dosock; //접속한 상대의 정보
HANDLE hFile; //각 각 파일의 정보
DWORD lsize; //실제 받아온 파일의 총 크기
char buf[1000]; //정보를담을수있는공간
WSABUF wb; //윈도우 소켓 버퍼에 대한 정보 포함
int cnt; //테스트 카운트를 위한 변수
MyOver() //테스트를 위한 함수
{
pcnt++;
cnt = pcnt;
}
};
// 구조체를사용하는이유
// : 여러 개의 대상이 오는데 거기에 필요한 정보를 받아오기 위해서 !!
void main()
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2,2),&wsadata);
SOCKET sock;
//오버랩 입출력이 가능한 소켓 생성
SOCKADDR_IN servaddr={0,};
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.34.91");
servaddr.sin_port = htons(11800);
bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
listen(sock,5);
SOCKADDR_IN clientaddr={0,};
int len = sizeof(clientaddr);
DWORD flag=0;
MyOver *mo;
while(1) //올 때까지 대기, 매번 다른 대상
{
mo = new MyOver; //생성 및 초기화
memset(&(mo->ol),0,sizeof(mo->ol));
mo->dosock = accept(sock,(SOCKADDR *)&clientaddr,&len);
// 접속된 소켓을 mo->dosock에 대입
mo->hFile = INVALID_HANDLE_VALUE;
mo->wb.len = 1000;
mo->wb.buf = mo->buf;
/Recv 시작 !
WSARecv(mo->dosock, &(mo->wb), 1, &rcnt, &flag, (WSAOVERLAPPED *)mo, ComRoutine);
}
WSACleanup();
}
void CALLBACK ComRoutine( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
DWORD flag=0;
MyOver *mo = (MyOver *)lpOverlapped;
SOCKET ds = mo->dosock;
char fname[256];
DWORD attributes;
if(cbTransferred) // 받아온 데이터의 크기
{
if(mo->hFile == INVALID_HANDLE_VALUE)
{
strcpy(fname, mo->buf);
attributes = *((int *)(mo->buf+FNLEN));
mo->lsize = *((int *)(mo->buf+FNLEN + sizeof(int)));
mo->hFile = CreateFile(fname,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
printf("%s파일다운시작%d\n",fname,mo->lsize);
if(mo->hFile == INVALID_HANDLE_VALUE)
{
printf("%s 파일생성오류\n",fname);
return;
}
}
else
{
DWORD dwWritten;
if(mo->lsize >1000)
{
WriteFile(mo->hFile,mo->wb.buf,1000,&dwWritten,0);
mo->lsize -= 1000;
}
else
{
WriteFile(mo->hFile,mo->wb.buf,mo->lsize,&dwWritten,0);
CloseHandle(mo->hFile);
closesocket(ds);
printf("%d다운로드완료\n",mo->cnt);
delete mo;
return;
}
}
if(mo->lsize <1000)
{
mo->wb.len = mo->lsize;
}
memset(&(mo->ol),0,sizeof(mo->ol));
WSARecv(ds,&(mo->wb),1,&rcnt,&flag,lpOverlapped,ComRoutine);
}
else
{
CloseHandle(mo->hFile);
closesocket(ds);
delete mo;
}
}
|