-
WindowsPlatform/소켓 2009. 2. 14. 17:52#include <wininet.h>
InternetOpen()
InternetConnect()
InternetOpenUrl()
INTERNET_FLAG_DONT_CACHE
InternetCloseHandle()
InternetQueryDataAvailable()
InternetReadFile()
요청한 크기보다 작을 수 있다.
InternetWriteFile()
InternetCrackUrl()
InternetSetFilePointer()
로컬 PC의 캐시에 적용되기 때문에 큰 파일에는 사용하면 안될 것 같음 // ???InternetSetStatusCallback()
InternetSetOption()
UDP 서버는 소켓이 하나만 있으면 된다.
#define FD_SETSIZE 200
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
WSAStartup()
WSACleanup()
getaddrinfo()
freeaddrinfo()
getnameinfo()
WSAStringToAddress()
WSAAddressToString()
/*
inet_addr()
inet_ntoa()
gethostbyname()
WSAAsyncGetHostByName()
gethostbyaddr()
WSAAsyncGetHostByAddr()
WSACancelAsyncRequest()
getservbyname()
WSAAsyncGetServByName()
getservbyport()
WSAAsyncGetServByPort()
getprotobyname()
WSAAsyncGetProtoByName()
getprotobynumber()
WSAAsyncGetProtoByNumber()
*/
socket()
connect()
closesocket()
send()
넌블로킹 소켓인 경우 보낸 데이터가 요청한 크기보다 작을 수 있다. // TCP??
recv()
수신한 데이터가 요청한 크기보다 작을 수 있다. // TCP??sendto()
recvfrom()
select()
WSAAsyncSelect()
소켓 이벤트를 윈도우 메시지로 비동기적으로 받을 수 있다.
비동기 데이타 송수신이 제공되는 것은 아니다.
FD_CLOSEFD_ACCEPT
FD_READ
FD_WRITE
readn()
writen()
readline()
BOOL bUdpConnect = FALSE; // Connect the UDP socket before sending?
WSADATA wsd;
char *addr = ...;
char *port = ...;
struct addrinfo hints, *res = NULL, *ptr=NULL;
int rc;
SOCKET s;
char *buf=NULL;
int buflen;
// Load Winsock
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
fprintf(stderr, "unable to load Winsock!\n");
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = 0;
hints.ai_family = af;
hints.ai_socktype = type;
hints.ai_protocol = proto;
rc = getaddrinfo(
addr,
port,
&hints,
&res
);
if (rc != 0)
{
printf("Invalid address %s, getaddrinfo failed: %d\n", addr, rc);
return -1;
}
// Iterate through each address resolved from the server's name
ptr = res;
while (ptr)
{
// create the socket
s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (s == INVALID_SOCKET)
{
fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
return -1;
}
if ((gProtocol == IPPROTO_TCP) || (bUdpConnect))
{
rc = connect(s, ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
printf("connect failed: %d\n", WSAGetLastError());
closesocket(s);
s = INVALID_SOCKET;
}
else
{
break;
}
}
else
{
// Option is UDP with no connect, just take first address and go with it
break;
}
// move to the next address resolved
ptr = ptr->ai_next;
}
// See if we've got a good connection
if (s == INVALID_SOCKET)
{
fprintf(stderr, "Unable to connect to server via resolved address(es)\n");
return -1;
}
// Allocate the send buffer
buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BYTE) * gBufferSize);
if (buf == NULL)
{
fprintf(stderr, "ReceiveThread: HeapAlloc failed: %d\n", GetLastError());
return -1;
}
buflen = gBufferSize;
memset(buf, '#', buflen);
if ((gProtocol == IPPROTO_TCP) || (bUdpConnect))
{
idx = 0;
nleft = buflen;
while (nleft > 0)
{
rc = send(s, &buf[idx], nleft, 0);
if (rc == SOCKET_ERROR)
{
fprintf(stderr,"send failed: %d\n", WSAGetLastError());
return -1;
}
nleft -= rc;
idx += rc;
}
rc = buflen;
}
else
{
rc = sendto(s, buf, buflen, 0, ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
// Its UDP so any failure we encounter is not likely to be serious
fprintf(stderr, "sendto failed: %d\n", WSAGetLastError());
}
}
/*
if (rc > 0)
{
}
*/
// If TCP, shutdown the socket to indicate no more sends. For UDP
// send three zero byte datagrams.
if (gProtocol == IPPROTO_TCP)
{
shutdown(s, SD_SEND);
}
else
{
for(i=0; i < 3 ;i++)
{
rc = sendto(
s,
buf,
0,
0,
ptr->ai_addr,
ptr->ai_addrlen
);
}
}
// Free the send buffer
HeapFree(GetProcessHeap(), 0, buf);
// Allocate the receive buffer for this socket
buflen = gBufferSize;
buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BYTE) * buflen);
if (buf == NULL)
{
fprintf(stderr, "HeapAlloc failed: %d\n", WSAGetLastError());
return -1;
}
while (1)
{
if (gProtocol == IPPROTO_UDP)
{
SOCKADDR_STORAGE addr;
int addrlen;
addrlen = sizeof(addr);
rc = recvfrom(
s,
buf,
buflen,
0,
(SOCKADDR *)&addr,
&addrlen
);
}
else if (gProtocol == IPPROTO_TCP)
{
rc = recv(
s,
buf,
buflen,
0
);
}
if ((rc == SOCKET_ERROR) || (rc == 0))
{
// Either a zero byte datagram was read (UDP), the connection was
// gracefully closed (TCP), or an error occured on the recv
break;
}
/*
else
{
}
*/
}
// Free the receive buffer
HeapFree(GetProcessHeap(), 0, buf);
freeaddrinfo(res);
closesocket(s);
WSACleanup();
return 0;
WSADATA wsd;
SOCKET s;
char *szPort = "5150";
struct addrinfo hints;
struct addrinfo *res=NULL,
*ptr=NULL;
int rc;
SOCKADDR_STORAGE addr; // Address data was received from (UDP)
int addrlen; // Length of address
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
fprintf(stderr, "unable to load Winsock!\n");
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE);
hints.ai_family = AF_UNSPEC; // unspecified
hints.ai_socktype = SOCK_STREAM; // TCP socket type
hints.ai_protocol = IPPROTO_TCP; // TCP protocol
rc = getaddrinfo(
NULL, // local interface to bind to
szPort,
&hints,
&res
);
if (rc != 0)
{
printf("Invalid address %s, getaddrinfo failed: %d\n", addr, rc);
return NULL;
}
// For each local address returned, create a listening/receiving socket
ptr = res;
// create the socket
s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (s == INVALID_SOCKET)
{
fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
return -1;
}
// bind the socket to a local address and port
rc = bind(s, ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
return -1;
}
// free the addrinfo structure for the 'bind' address
freeaddrinfo(res);
if (gProtocol == IPPROTO_UDP)
{
// If we're UDP we don't have any "connections" to handle. we just have to
// receive UDP packets and send them back.
//
// For UDP all we do is receive packets on the port
while (1)
{
char *buf=NULL;
int buflen;
...
rc = recvfrom(
s,
buf,
buflen,
0,
(SOCKADDR *)&addr,
&addrlen);
buflen = rc;
/*
if (rc > 0)
{
}
*/
// For UDP we send the packet back to the source address
rc = sendto(
s,
buf,
buflen,
0,
(SOCKADDR *)&addr,
addrlen
);
if (buflen == 0)
{
break;
}
}
}
else if (gProtocol == IPPROTO_TCP)
{
SOCKADDR_STORAGE saAccept; // client address
SOCKET ns; // client socket
int acceptlen = sizeof(SOCKADDR_STORAGE);
int nleft, idx;
rc = listen(s, 200);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
return -1;
}
while (1)
{
// Wait for an incoming client connection
ns = accept(s, (SOCKADDR *)&saAccept, &acceptlen);
if (ns == INVALID_SOCKET)
{
fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
return -1;
}
// loop until the connection is closed or is aborted/terminated
while (1)
{
char *buf=NULL;
int buflen;
...
rc = recv(
ns,
buf,
buflen,
0);
buflen = rc;
if (rc == 0 || rc == SOCKET_ERROR)
{
break;
}
/*
else if (rc != SOCKET_ERROR)
{
}
*/
// Otherwise send the buffer on the connection socket
nleft = buflen;
idx = 0;
while (nleft > 0)
{
rc = send(
ns,
&buf[idx],
nleft,
0
);
if (rc == SOCKET_ERROR)
{
break;
}
else
{
nleft -= rc;
idx += rc;
}
}
if (rc == SOCKET_ERROR)
{
printf("Send(to) failed: %d\n", WSAGetLastError());
break;
}
/*
else if (rc > 0)
{
}
*/
}
closesocket(ns);
}
closesocket(s);
WSACleanup();
return 0;
// GetHTTP.cpp
//
// Retrieves a file using the Hyper Text Transfer Protocol
// and prints its contents to stdout.
//
// Pass the server name and full path of the file on the
// command line and redirect the output to a file. The program
// prints messages to stderr as it progresses.
//
// Example:
// GetHTTP www.idgbooks.com /index.html > index.html
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <winsock.h>
#pragma comment(lib, "ws2_32")
void GetHTTP(LPCSTR lpServerName, LPCSTR lpFileName);
// Helper macro for displaying errors
#define PRINTERROR(s) \
fprintf(stderr,"\n%s: %d\n", s, WSAGetLastError())
void main(int argc, char **argv)
{
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsaData;
int nRet;
// Check arguments
if (argc != 3)
{
fprintf(stderr,
"\nSyntax: GetHTTP ServerName FullPathName\n");
return;
}
// Initialize WinSock.dll
nRet = WSAStartup(wVersionRequested, &wsaData);
if (nRet)
{
fprintf(stderr,"\nWSAStartup(): %d\n", nRet);
WSACleanup();
return;
}
// Check WinSock version
if (wsaData.wVersion != wVersionRequested)
{
fprintf(stderr,"\nWinSock version not supported\n");
WSACleanup();
return;
}
// Set "stdout" to binary mode
// so that redirection will work
// for .gif and .jpg files
_setmode(_fileno(stdout), _O_BINARY);
// Call GetHTTP() to do all the work
GetHTTP(argv[1], argv[2]);
// Release WinSock
WSACleanup();
}
void GetHTTP(LPCSTR lpServerName, LPCSTR lpFileName)
{
// Use inet_addr() to determine if we're dealing with a name
// or an address
IN_ADDR iaHost;
LPHOSTENT lpHostEntry;
iaHost.s_addr = inet_addr(lpServerName);
if (iaHost.s_addr == INADDR_NONE)
{
// Wasn't an IP address string, assume it is a name
lpHostEntry = gethostbyname(lpServerName);
}
else
{
// It was a valid IP address string
lpHostEntry = gethostbyaddr((const char *)&iaHost,
sizeof(struct in_addr), AF_INET);
}
if (lpHostEntry == NULL)
{
PRINTERROR("gethostbyname()");
return;
}
// Create a TCP/IP stream socket
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket == INVALID_SOCKET)
{
PRINTERROR("socket()");
return;
}
// Find the port number for the HTTP service on TCP
LPSERVENT lpServEnt;
SOCKADDR_IN saServer;
lpServEnt = getservbyname("http", "tcp");
if (lpServEnt == NULL) saServer.sin_port = htons(80);
else saServer.sin_port = lpServEnt->s_port;
// Fill in the rest of the server address structure
saServer.sin_family = AF_INET;
saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
// Connect the socket
int nRet;
nRet = connect(Socket, (LPSOCKADDR)&saServer, sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR)
{
PRINTERROR("connect()");
closesocket(Socket);
return;
}
// Format the HTTP request
char szBuffer[1024];
sprintf(szBuffer, "GET %s\n", lpFileName);
nRet = send(Socket, szBuffer, strlen(szBuffer), 0);
if (nRet == SOCKET_ERROR)
{
PRINTERROR("send()");
closesocket(Socket);
return;
}
// Receive the file contents and print to stdout
while(1)
{
// Wait to receive, nRet = NumberOfBytesReceived
nRet = recv(Socket, szBuffer, sizeof(szBuffer), 0);
if (nRet == SOCKET_ERROR)
{
PRINTERROR("recv()");
break;
}
fprintf(stderr,"\nrecv() returned %d bytes", nRet);
// Did the server close the connection?
if (nRet == 0) break;
// Write to stdout
fwrite(szBuffer, nRet, 1, stdout);
}
closesocket(Socket);
}
//
// Allocated for each receiver posted
// Each receive thread allocates one of these for a receive operation.
// After data is read, this object is queued for the send thread to
// echo back to the client (sender).
//
typedef struct _BUFFER_OBJ
{
char *buf; // Data buffer for data
int buflen; // Length of buffer or number of bytes contained in buffer
SOCKADDR_STORAGE addr; // Address data was received from (UDP)
int addrlen; // Length of address
struct _BUFFER_OBJ *next;
} BUFFER_OBJ;
//
// Allocated for each client connection
//
typedef struct _CONNECTION_OBJ
{
SOCKET s; // Client socket
HANDLE hRecvSema; // Semaphore incremented for each receive
struct _BUFFER_OBJ *PendingSendHead, // List of pending buffers to send
*PendingSendTail; // End of the list
CRITICAL_SECTION SendRecvQueueCritSec; // Protect access to this structure
} CONNECTION_OBJ;
//
// Function: GetConnectionObj
//
// Description:
// This routine allocates a CONNECTION_OBJ structure and initializes its
// members. For sake of simplicity, this routine allocates a object from
// the process heap. For better performance, you should modify this to
// maintain a lookaside list of structures already allocated and freed
// and only allocate from the heap when necessary.
//
CONNECTION_OBJ *GetConnectionObj(SOCKET s)
{
CONNECTION_OBJ *newobj=NULL;
// Allocate the object
newobj = (CONNECTION_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONNECTION_OBJ));
if (newobj == NULL)
{
printf("GetConnectionObj: HeapAlloc failed: %d\n", WSAGetLastError());
ExitProcess(-1);
}
newobj->s = s;
// Create the semaphore for signaling the send thread
newobj->hRecvSema = CreateSemaphore(NULL, 0, 0x0FFFFFFF, NULL);
if (newobj->hRecvSema == NULL)
{
fprintf(stderr, "GetConnectionObj: CreateSemaphore failed: %d\n", GetLastError());
ExitProcess(-1);
}
InitializeCriticalSection(&newobj->SendRecvQueueCritSec);
return newobj;
}
//
// Function: FreeConnectionObj
//
// Description:
// This routine frees a CONNECTIN_OBJ. It first frees the critical section.
// See the comment for GetConnectionObj about using lookaside lists.
//
void FreeConnectionObj(CONNECTION_OBJ *obj)
{
DeleteCriticalSection(&obj->SendRecvQueueCritSec);
HeapFree(GetProcessHeap(), 0, obj);
}
//
// Function: GetBufferObj
//
// Description:
// Allocate a BUFFER_OBJ. Each receive posted by a receive thread allocates
// one of these. After the recv is successful, the BUFFER_OBJ is queued for
// sending by the send thread. Again, lookaside lists may be used to increase
// performance.
//
BUFFER_OBJ *GetBufferObj(int buflen)
{
BUFFER_OBJ *newobj=NULL;
// Allocate the object
newobj = (BUFFER_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BUFFER_OBJ));
if (newobj == NULL)
{
fprintf(stderr, "GetBufferObj: HeapAlloc failed: %d\n", GetLastError());
ExitProcess(-1);
}
// Allocate the buffer
newobj->buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BYTE) *buflen);
if (newobj->buf == NULL)
{
fprintf(stderr, "GetBufferObj: HeapAlloc failed: %d\n", GetLastError());
ExitProcess(-1);
}
newobj->buflen = buflen;
newobj->addrlen = sizeof(newobj->addr);
return newobj;
}
//
// Function: FreeBufferObj
//
// Description:
// Free the buffer object.
//
void FreeBufferObj(BUFFER_OBJ *obj)
{
HeapFree(GetProcessHeap(), 0, obj->buf);
HeapFree(GetProcessHeap(), 0, obj);
}
//
// Function: EnqueueBufferObj
//
// Description:
// Queue up a receive buffer for this connection. After enqueueing the receiver
// will release the counting semaphore which will release the sender to
// dequeue a buffer and send it.
//
void EnqueueBufferObj(CONNECTION_OBJ *conn, BUFFER_OBJ *obj)
{
EnterCriticalSection(&conn->SendRecvQueueCritSec);
if (conn->PendingSendHead == NULL)
{
// Queue is empty
conn->PendingSendHead = conn->PendingSendTail = obj;
}
else
{
// Put new object at the end
conn->PendingSendTail->next = obj;
conn->PendingSendTail = obj;
}
LeaveCriticalSection(&conn->SendRecvQueueCritSec);
}
//
// Function: DequeueBufferObj
//
// Description:
// Remove a BUFFER_OBJ from the given connection's queue for sending.
//
BUFFER_OBJ *DequeueBufferObj(CONNECTION_OBJ *conn)
{
BUFFER_OBJ *ret=NULL;
EnterCriticalSection(&conn->SendRecvQueueCritSec);
if (conn->PendingSendTail != NULL)
{
// Queue is non empty
ret = conn->PendingSendHead;
conn->PendingSendHead = conn->PendingSendHead->next;
if (conn->PendingSendTail == ret)
{
// Item is the only item in the queue
conn->PendingSendTail = NULL;
}
}
LeaveCriticalSection(&conn->SendRecvQueueCritSec);
return ret;
}
//
// Function: ReceiveThead
//
// Description:
// One of these threads is started for each client connection.
// This thread sits in a loop, receiving data. For each receive, the
// buffer is queued for sending by the SenderThread for this connection.
//
DWORD WINAPI ReceiveThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
BUFFER_OBJ *BuffObj=NULL;
int rc;
// Retrieve the connection object for this connection
ConnObj = (CONNECTION_OBJ *)lpParam;
if (gProtocol == IPPROTO_UDP)
{
// For UDP all we do is receive packets on the port
while (1)
{
// Allocate the buffer for datagram send/recv
BuffObj = GetBufferObj(gBufferSize);
rc = recvfrom(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0,
(SOCKADDR *)&BuffObj->addr,
&BuffObj->addrlen);
BuffObj->buflen = rc;
/*
if (rc > 0)
{
}
*/
// Queue the receive buffer for sending and signal the send thread
EnqueueBufferObj(ConnObj, BuffObj);
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0)
{
break;
}
}
}
else if (gProtocol == IPPROTO_TCP)
{
// loop until the connection is closed or is aborted/terminated
while (1)
{
// Allocate the buffer for stream send/recv
BuffObj = GetBufferObj(gBufferSize);
rc = recv(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0);
BuffObj->buflen = rc;
// Queue the receive buffer for sending and signal the send thread
EnqueueBufferObj(ConnObj, BuffObj);
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0 || rc == SOCKET_ERROR)
{
break;
}
/*
else if (rc != SOCKET_ERROR)
{
}
*/
}
}
ExitThread(0);
return 0;
}
//
// Function: SendThread
//
// Description:
// This is the send thread started for each client connection.
// This thread waits for the semaphore to be signaled indicating that
// the receive thread has queued a buffer for sending.
//
DWORD WINAPI SendThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
BUFFER_OBJ *BuffObj=NULL;
int rc,
nleft,
idx;
// Retrieve the connection object
ConnObj = (CONNECTION_OBJ *)lpParam;
while (1)
{
// Wait for the receive thread to signal us
rc = WaitForSingleObject(ConnObj->hRecvSema, INFINITE);
if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
ExitProcess(-1);
}
// Retrieve the first buffer from this connection's queue
BuffObj = DequeueBufferObj(ConnObj);
//
// If the this receive by the receive thread indicated zero bytes then
// the connection has been gracefully closed. Otherwise, if an error
// was indicated then the connection was aborted.
//
if ((gProtocol == IPPROTO_TCP ) && ((BuffObj->buflen == 0) || (BuffObj->buflen == SOCKET_ERROR)))
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
if (gProtocol == IPPROTO_UDP)
{
// For UDP we send the packet back to the source address
rc = sendto(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0,
(SOCKADDR *)&BuffObj->addr,
BuffObj->addrlen
);
if (BuffObj->buflen == 0)
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
}
else if (gProtocol == IPPROTO_TCP)
{
// Otherwise send the buffer on the connection socket
nleft = BuffObj->buflen;
idx = 0;
while (nleft > 0)
{
rc = send(
ConnObj->s,
&BuffObj->buf[idx],
nleft,
0
);
if (rc == SOCKET_ERROR)
{
break;
}
else
{
nleft -= rc;
idx += rc;
}
}
}
if (rc == SOCKET_ERROR)
{
printf("SendThread: send(to) failed: %d\n", WSAGetLastError());
break;
}
/*
else if (rc > 0)
{
}
*/
FreeBufferObj(BuffObj);
BuffObj = NULL;
}
// Close the connection's socket
closesocket(ConnObj->s);
FreeConnectionObj(ConnObj);
ExitThread(0);
return 0;
}
//
// Funtion: ServerListenThread
//
// Description:
// This function is spawned for each listening or receive thread
// depending on whether the server is started for UDP or TCP. In
// reality there will only be two server threads, one for IPv4
// and one for IPv6.
//
DWORD WINAPI ServerListenThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
HANDLE hThread = NULL;
SOCKET s;
int rc;
s = (SOCKET) lpParam;
if (gProtocol == IPPROTO_UDP)
{
// If we're UDP we don't have any "connections" to handle. we just have to
// receive UDP packets and send them back. Hence we only need 1 receiver
// thread and 1 sender thread for the whole thing.
//
ConnObj = GetConnectionObj(s);
hThread = CreateThread(NULL, 0, ReceiveThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "ServerListenThread: CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
SendThread((LPVOID)ConnObj);
}
else if (gProtocol == IPPROTO_TCP)
{
SOCKADDR_STORAGE saAccept; // client address
SOCKET ns; // client socket
int acceptlen = sizeof(SOCKADDR_STORAGE);
rc = listen(s, 200);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
ExitThread(-1);
}
while (1)
{
// Wait for an incoming client connection
ns = accept(s, (SOCKADDR *)&saAccept, &acceptlen);
if (ns == INVALID_SOCKET)
{
fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
return -1;
}
// Allocate a connection object for this client
ConnObj = GetConnectionObj(ns);
// Create a receiver thread for this connection
hThread = CreateThread(NULL, 0, ReceiveThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
CloseHandle(hThread);
// Create a sender thread for this connection
hThread = CreateThread(NULL, 0, SendThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
CloseHandle(hThread);
}
}
closesocket(s);
ExitThread(0);
return 0;
}
멀티캐스트
멀티캐스트 그룹에 속해 있는 모든 호스트들에게 데이터를 전송
UDP를 기반으로 한다.
브로드 캐스트
동일한 네트워크에 연결되어 있는 호스트들에게 패킷을 전송
기본적인 데이터 전송 방식은 UDP를 사용한다.
참조 사이트:
http://serious-code.net/moin.cgi/RetrievingFileUsingHttp#head-3bb0a3010d4af014c3ab126cdcda04d308067ca5
http://support.microsoft.com/default.aspx?scid=kb;en-us;224318
http://support.microsoft.com/kb/111855/en-us/
http://jjjryu.tistory.com/entry/POSIX-1
http://wwwi.tistory.com/70