`
java-mans
  • 浏览: 11420812 次
文章分类
社区版块
存档分类
最新评论

《ASCE1885的网络编程》---Winsock API基本函数の数据传输

 
阅读更多

Winsock,用于数据发送和接收的系统调用分为两组:一组是有连接的数据发送和接收系统调用;一组是无连接的数据发送和接收系统调用。这里我们先弄清与数据发送和接收关系密切的“带外数据”的概念。

1)带外数据概念:

有时我们可能要传输一些相对来说比较重要的数据,如果按普通数据进行传送,那么在传输过程中要受流量、拥挤等控制的影响。对于这些比普通数据重要的数据,在传输过程中可以标记为带外数据(Out-Of-BandOOB)。

对于带外数据,从逻辑上看,好像用户进程使用了一个独立的通道发送这些带外数据,位于连接另一端的应用进程通过一个独立的逻辑信道来接收和处理带外数据。这样对于标记成带外数据的数据流,在传输时可减少传输系统对数据的干预。

TCP协议中,OOB数据由一个紧急位(URG)和TCP段头中的一个16位的紧急数据指针标记,把指定的数据流当作紧急数据来处理。

Winsock中,要查看待发数据中是否包含紧急数据,必须通过SIOCATMARK选项调用ioctlsocket函数来实现。Winsock提供了获得紧急数据的方法:一是紧急数据一旦在线插入,它就会出现在普通数据流中;二是可以关闭在线插入,这样,不连续调用接收函数就会只返回紧急数据。控制OOB数据行为的套接口选项是SO_OOBINLINE

不同的系统对带外数据可能有不同的解释,所以在编写应用程序时为了增前程序的通用性,应该尽量不用带外数据。

1) 在已建立连接的套接口上发送数据---send()WSASend()

send()函数是在Winsock1中提供的,具体见:《Windows API巡礼》---sendrecv(http://blog.csdn.net/ACE1985/archive/2010/07/03/5710734.aspx )

Winsock2中提供的函数扩展格式是WSASend()

int WSASend(

__in SOCKET s, //用于标识已建立连接的套接口描述字

__in LPWSABUF lpBuffers, //指向WSABUF结构数组的指针

__in DWORD dwBufferCount, //lpBuffer数组中WSABUF结构的数目

__out LPDWORD lpNumberOfBytesSent, //如果发送操作立即完成,

//则为一个指向所发送数据字节数的指针

__in DWORD dwFlags, //用于控制数据传输方式,可以是

//0---表示按正常方式发送数据

//MSG_DONTROUTE---表示系统目标主机就在直接连接的本地网络中,无需路由选择;

// 但如果传输协议的实现不支持该选项,则该标志被忽略

//MSG_OOB---表示数据是按带外数据发送的

__in LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED结构的指针(用于重叠套接口)

__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine //一个指向发送操作

//完成后调用的完成例程的指针(用于重叠套接口)

);

若无错误发生,WSASend()函数返回所发送的字节数,连接结束,函数返回0。在发生错误的情况下,返回返回SOCKET_ERROR错误,可通过WSAGetLastError函数获取相应错误代码。

send()函数适用于已建立连接的数据报或流式套接口发送数据。对于数据报类套接口,必须注意发送数据长度不应超过通信子网的IP包最大长度。IP包最大长度在WSAStartup()调用返回的WSAData结构的iMaxUdpDg元素中指定。如果数据太长无法自动通过下层协议,则返回WSAEMSGSIZE错误,数据不会被发送。

要注意,成功地完成send()调用并不意味着数据已可靠传送到目标。

如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞I/O方式,否则send()将阻塞。对于非阻塞SOCK_STREAM类型的套接口,实际写的数据数目可能在1到所需大小之间,其值取决于本地和远端主机的缓冲区大小。可用select()调用来确定何时能够进一步发送数据。

在相关套接口的选项之上,还可通过标志位flag来影响函数的执行方式,也就是说,本函数的语义既取决于套接口的选项,又取决于标志位。

以下实例代码演示了在重叠I/O模式下WSASend函数的用法:

#include <windows.h>

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <stdlib.h>

#pragma comment(lib, "ws2_32.lib")

#define DATA_BUFSIZE 4096

#define SEND_COUNT 10

int main()

{

WSADATA wsaData;

struct addrinfo *result = NULL;

struct addrinfo hints = {0};

WSAOVERLAPPED SendOverlapped = {0};

SOCKET ListenSocket = INVALID_SOCKET;

SOCKET AcceptSocket = INVALID_SOCKET;

WSABUF DataBuf;

DWORD SendBytes;

DWORD Flags;

char buffer[DATA_BUFSIZE];

int err, rc, i;

//Load winsock

rc = WSAStartup(MAKEWORD(2,2), &wsaData);

if(rc != 0)

{

fprintf(stderr, "Unable to load winsock: %d/n", rc);

return 1;

}

//Initialize the hints to obtain the

//wildcard bind address for IPv4

hints.ai_family = AF_INET;

hints.ai_socktype = SOCK_STREAM;

hints.ai_protocol = IPPROTO_TCP;

hints.ai_flags = AI_PASSIVE;

rc = getaddrinfo(NULL, "27015", &hints, &result);

if(rc != 0)

{

fprintf(stderr, "getaddrinfo faild: %d/n", rc);

return 1;

}

ListenSocket = socket(result->ai_family,

result->ai_socktype, result->ai_protocol);

if(ListenSocket == INVALID_SOCKET)

{

fprintf(stderr, "socket failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

return 1;

}

rc = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);

if(rc == SOCKET_ERROR)

{

fprintf(stderr, "bind failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

closesocket(ListenSocket);

return 1;

}

rc = listen(ListenSocket, 1);

if(rc == SOCKET_ERROR)

{

fprintf(stderr, "listen failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

closesocket(ListenSocket);

return 1;

}

//Accept an incoming connection request

AcceptSocket = accept(ListenSocket, NULL, NULL);

if(AcceptSocket == INVALID_SOCKET)

{

fprintf(stderr, "accept failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

closesocket(ListenSocket);

return 1;

}

printf("Client Accepted.../n");

//Create an event handle and setup an overlapped structure

SendOverlapped.hEvent = WSACreateEvent();

if(SendOverlapped.hEvent == NULL)

{

fprintf(stderr, "WSACreateEvent failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

closesocket(ListenSocket);

closesocket(AcceptSocket);

return 1;

}

DataBuf.len = DATA_BUFSIZE;

DataBuf.buf = buffer;

for(i=0; i<SEND_COUNT; i++)

{

rc = WSASend(AcceptSocket, &DataBuf, 1,

&SendBytes, 0, &SendOverlapped, NULL);

if(rc == SOCKET_ERROR &&

(WSA_IO_PENDING != (err = WSAGetLastError())))

{

fprintf(stderr, "WSASend failed: %d/n", err);

break;

}

rc = WSAWaitForMultipleEvents(1, &SendOverlapped.hEvent, TRUE, INFINITE, TRUE);

if(rc == WSA_WAIT_FAILED)

{

fprintf(stderr, "WSAWaitForMultipleEvents failed: %d/n", WSAGetLastError());

break;

}

rc = WSAGetOverlappedResult(AcceptSocket, &SendOverlapped, &SendBytes,

FALSE, &Flags);

if(rc == FALSE)

{

fprintf(stderr, "WSASend operation failed: %d/n", WSAGetLastError());

break;

}

printf("Wrote %d bytes/n", SendBytes);

WSAResetEvent(SendOverlapped.hEvent);

}

WSACloseEvent(SendOverlapped.hEvent);

closesocket(AcceptSocket);

closesocket(ListenSocket);

freeaddrinfo(result);

WSACleanup();

system("pause");

return 0;

}

2) 在已建立连接的套接口上接收数据---recv()WSARecv()

Winsock1中提供的recv()函数的原型,具体见:《Windows API巡礼》---sendrecv(http://blog.csdn.net/ACE1985/archive/2010/07/03/5710734.aspx )

Winsock2中提供的函数扩展是WSARecv()

int WSARecv(

__in SOCKET s, //已建立连接的套接口描述字

__inout LPWSABUF lpBuffers, //指向WSABUF结构数组的指针,每一个WSABUF结构包含一个缓冲区

//的指针和缓冲区的长度

__in DWORD dwBufferCount, //lpBuffers数组中WSABUF结构的数目

__out LPDWORD lpNumberOfBytesRecvd, //如果接收操作立即结束,

//该参数指向本调用所接收的字节数的指针

__inout LPDWORD lpFlags, //指定调用方式,0---表示接收的是正常数据;

//MSG_PEEK---表示会使有用的数据复制到所提供的接收端缓冲区内,但是没有从系统

//缓冲区中将数据删除。

//MSG_OOB---表示处理带外数据

__in LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED结构的指针

//(对于非重叠套接口忽略之)

__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine //指向接收操作结束

//后调用的例程的指针(非重叠套接口忽略之)

);

函数调用成功返回所接收到的字节数,函数在连接结束时返回0。如果发生错误,返回SOCKET_ERROR错误信息,可通过WSAGetLastError()获取相应错误代码。

本函数用于已建立连接的数据报或流式套接口上进行数据的接收。

对于SOCK_STREAM类型的套接口来说,本函数将返回所有可用的信息,最大可达缓冲区的大小。如果套接口被设置为在线接收带外数据(选项为SO_OOBINLINE),且有带外数据未读入,则返回带外数据。应用程序可通过调用ioctlsocket()SIOCATMARK命令来确定是否有带外数据待读入。

对于数据报套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recv()函数返回WSAEMSGSIZE错误。

但对于流式传输协议来说,就不会碰到WSAEMSGSIZE错误。

如果没有数据待读,那么除非是非阻塞模式,否则套接口将一直等待数据的到来,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()WSAAsyncSelect()可以获知数据何时到达。

如果套接口为SOCK_STREAM类型,并且远端“优雅”地中止了连接,那么recv()一个数据也不读取,立即返回。如果连接被强制中止,那么recv()将以WSAECONNRESET错误失败返回。

下面的代码实例演示了在重叠I/O模式下WSARecv的使用:

#include <windows.h>

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable: 4127) // Conditional expression is a constant

#define DATA_BUFSIZE 4096

void __cdecl main(int argc, char **argv)

{

WSADATA wsd;

struct addrinfo *result = NULL,

*ptr = NULL,

hints = {0};

WSAOVERLAPPED RecvOverlapped = {0};

SOCKET ConnSocket = INVALID_SOCKET;

WSABUF DataBuf;

DWORD RecvBytes, Flags;

char buffer[DATA_BUFSIZE];

int err, rc;

if (argc != 2) {

fprintf(stderr, "usage: %s server-name/n", argv[0]);

return;

}

// Load Winsock

rc = WSAStartup(MAKEWORD(2,2), &wsd);

if (rc != 0) {

fprintf(stderr, "Unable to load Winsock: %d/n", rc);

return;

}

// Initialize the hints to retrieve the server address for IPv4

hints.ai_family = AF_INET;

hints.ai_socktype = SOCK_STREAM;

hints.ai_protocol = IPPROTO_TCP;

rc = getaddrinfo(argv[1], "27015", &hints, &result);

if (rc != 0) {

fprintf(stderr, "getaddrinfo failed: %d/n", rc );

return;

}

for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

if (ConnSocket == INVALID_SOCKET) {

fprintf(stderr, "socket failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

return;

}

rc = connect(ConnSocket, ptr->ai_addr, (int)ptr->ai_addrlen);

if (rc == SOCKET_ERROR) {

if (WSAECONNREFUSED == (err = WSAGetLastError())) {

closesocket(ConnSocket);

ConnSocket = INVALID_SOCKET;

continue;

}

fprintf(stderr, "connect failed: %d/n", err);

freeaddrinfo(result);

closesocket(ConnSocket);

return;

}

break;

}

if ( ConnSocket == INVALID_SOCKET ) {

fprintf(stderr, "Unable to establish connection with the server!/n");

freeaddrinfo(result);

return;

}

printf("Client connected.../n");

// Create an event handle and setup an overlapped structure.

RecvOverlapped.hEvent = WSACreateEvent();

if (RecvOverlapped.hEvent == NULL) {

fprintf(stderr, "WSACreateEvent failed: %d/n", WSAGetLastError());

freeaddrinfo(result);

closesocket(ConnSocket);

return;

}

DataBuf.len = DATA_BUFSIZE;

DataBuf.buf = buffer;

// Call WSARecv until the peer closes the connection

// or until an error occurs

while(1) {

Flags = 0;

rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);

if ( (rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {

fprintf(stderr, "WSARecv failed: %d/n", err);

break;

}

rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);

if (rc == WSA_WAIT_FAILED) {

fprintf(stderr, "WSAWaitForMultipleEvents failed: %d/n", WSAGetLastError());

break;

}

rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);

if (rc == FALSE) {

fprintf(stderr, "WSARecv operation failed: %d/n", WSAGetLastError());

break;

}

printf("Read %d bytes/n", RecvBytes);

WSAResetEvent(RecvOverlapped.hEvent);

// If 0 bytes are received, the connection was closed

if (RecvBytes == 0 )

break;

}

WSACloseEvent(RecvOverlapped.hEvent);

closesocket(ConnSocket);

freeaddrinfo(result);

WSACleanup();

return;

}

4)在无连接的套接口上接收数据---recvfrom()WSARecvFrom()

Winsock1中提供的recvfrom函数详见:《Windows API巡礼》---sendtorecvfromhttp://blog.csdn.net/ACE1985/archive/2010/07/03/5710856.aspx )。

Winsock2中提供的函数的扩展是WSARecvFrom

int WSARecvFrom(

__in SOCKET s, //一个标识套接口的描述字

__inout LPWSABUF lpBuffers, //一个指向WSABUF结构数组的指针,每个WSABUF结构包含缓冲区的

//指针和缓冲区的大小

__in DWORD dwBufferCount, //lpBuffers数组中WSABUF结构的数目

__out LPDWORD lpNumberOfBytesRecvd, //如果接收操作立即完成,

//则为一个指向所接收数据字节数的指针

__inout LPDWORD lpFlags, //调用操作方式,同WSARecv()中的lpFlags

__out struct sockaddr *lpFrom, //指向重叠操作完成后存放源地址的缓冲区

__inout LPINT lpFromlen, //指向lpfrom缓冲区大小的指针

__in LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED结构的指针

__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine //指向接收操作完成

//后调用的完成例程的指针

);

函数调用成功时,返回所接收的字节数,函数在接收结束时返回0;否则返回SOCKET_ERROR错误,可调用WSAGetLastError()获取相应的错误代码。

该函数的用法与有连接的recv()WSARecv()函数的用法类似,要注意的是该函数也可以用于有连接时数据的接收。

以下代码实例演示了函数WSARecvFrom的使用:

#include <windows.h>

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

int __cdecl main()

{

WSADATA wsaData;

WSABUF DataBuf;

WSAOVERLAPPED Overlapped = {0};

SOCKET RecvSocket = INVALID_SOCKET;

struct sockaddr_in RecvAddr;

struct sockaddr_in SenderAddr;

int SenderAddrSize = sizeof (SenderAddr);

int Port = 27015;

char RecvBuf[1024];

int BufLen = 1024;

DWORD BytesRecv = 0;

DWORD Flags = 0;

int err;

int rc;

int retval = 0;

//-----------------------------------------------

// Initialize Winsock

rc = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (rc != 0) {

/* Could not find a usable Winsock DLL */

printf("WSAStartup failed with error: %ld/n", err);

return 1;

}

// Create an event handle and setup an overlapped structure.

Overlapped.hEvent = WSACreateEvent();

if (Overlapped.hEvent == NULL) {

printf("WSACreateEvent failed: %d/n", WSAGetLastError());

WSACleanup();

return 1;

}

//-----------------------------------------------

// Create a receiver socket to receive datagrams

RecvSocket = WSASocket(AF_INET,

SOCK_DGRAM,

IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

if (RecvSocket == INVALID_SOCKET) {

/* Could not open a socket */

printf("WSASocket failed with error: %ld/n", WSAGetLastError());

WSACloseEvent(Overlapped.hEvent);

WSACleanup();

return 1;

}

//-----------------------------------------------

// Bind the socket to any address and the specified port.

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_port = htons(Port);

RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));

if (rc != 0) {

/* Bind to the socket failed */

printf("bind failed with error: %ld/n", WSAGetLastError());

WSACloseEvent(Overlapped.hEvent);

closesocket(RecvSocket);

WSACleanup();

return 1;

}

//-----------------------------------------------

// Call the recvfrom function to receive datagrams

// on the bound socket.

DataBuf.len = BufLen;

DataBuf.buf = RecvBuf;

printf("Listening for incoming datagrams on port=%d/n", Port);

rc = WSARecvFrom(RecvSocket,

&DataBuf,

1,

&BytesRecv,

&Flags,

(SOCKADDR *) & SenderAddr,

&SenderAddrSize, &Overlapped, NULL);

if (rc != 0) {

err = WSAGetLastError();

if (err != WSA_IO_PENDING) {

printf("WSARecvFrom failed with error: %ld/n", err);

WSACloseEvent(Overlapped.hEvent);

closesocket(RecvSocket);

WSACleanup();

return 1;

}

else {

rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);

if (rc == WSA_WAIT_FAILED) {

printf("WSAWaitForMultipleEvents failed: %d/n", WSAGetLastError());

retval = 1;

}

rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,

FALSE, &Flags);

if (rc == FALSE) {

printf("WSArecvFrom operation failed: %d/n", WSAGetLastError());

retval = 1;

}

else

printf("Number of received bytes = %d/n", BytesRecv);

printf("Finished receiving. Closing socket./n");

}

}

//---------------------------------------------

// When the application is finished receiving, close the socket.

WSACloseEvent(Overlapped.hEvent);

closesocket(RecvSocket);

printf("Exiting./n");

//---------------------------------------------

// Clean up and quit.

WSACleanup();

return (retval);

}

5)在无连接的套接口上发送数据---sendto()WSASendTo()

Winsock1中提供的sendto()函数详见:《Windows API巡礼》---sendtorecvfromhttp://blog.csdn.net/ACE1985/archive/2010/07/03/5710856.aspx )。

Winsock2中提供的函数扩展WSASendTo()

int WSASendTo(

__in SOCKET s, //标识一个套接口描述字

__in LPWSABUF lpBuffers, //一个指向WSABUF结构数组的指针,

//每个WSABUF结构包含缓冲区的指针和缓冲区的大小

__in DWORD dwBufferCount, //lpBuffers数组中WSABUF结构的数目

__out LPDWORD lpNumberOfBytesSent, //如果发送操作立即完成,

//则为一个指向所发送数据字节数的指针

__in DWORD dwFlags, //调用方式标志位,同WSASend()中该参数的含义

__in const struct sockaddr *lpTo, //指向目标套接口的地址

__in int iToLen, //lpTo中地址的大小

__in LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED结构的指针

__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine //指向发送操作完成

//后调用的完成例程的指针

);

函数调用成功,返回所发送的字节数,函数在连接结束时返回0;否则返回SOCKET_ERROR错误,可调用WSAGetLastError()函数获取相应错误代码。

这两个函数使用方法类似于send()WSASend()函数。当用于无连接的套接口时,调用函数之前要设置,指出目标IP地址和目标端口号。如果用于有连接的套接口时,则不能指定目标地址和端口,应将lpTo设置为空,地址长度设置为0。当然在有连接的情况下很少使用该函数。

以下实例代码演示了WSASendTo函数的使用:

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <windows.h>

int __cdecl main(int argc, char **argv)

{

//---------------------------------------------

// Declare and initialize variables

WSADATA wsaData;

WSABUF DataBuf;

WSAOVERLAPPED Overlapped = { 0 };

SOCKET SendToSocket = INVALID_SOCKET;

struct sockaddr_in RecvAddr;

struct sockaddr_in LocalAddr;

int RecvAddrSize = sizeof (RecvAddr);

int LocalAddrSize = sizeof (LocalAddr);

int Port = 27777;

struct hostent *localHost;

char *ip;

char *targetip;

char *targetport;

char SendBuf[1024] = "Data buffer to send";

int BufLen = 1024;

DWORD BytesSent = 0;

DWORD Flags = 0;

int rc, err;

int retval = 0;

// Validate the parameters

if (argc != 3) {

printf("usage: %s targetip port/n", argv[0]);

printf(" to sendto the localhost on port 27777/n");

printf(" %s 127.0.0.1 27015/n", argv[0]);

return 1;

}

targetip = argv[1];

targetport = argv[2];

//---------------------------------------------

// Initialize Winsock

// Load Winsock

rc = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (rc != 0) {

fprintf(stderr, "Unable to load Winsock: %d/n", rc);

return 1;

}

// Create an event handle and setup an overlapped structure.

Overlapped.hEvent = WSACreateEvent();

if (Overlapped.hEvent == NULL) {

fprintf(stderr, "WSACreateEvent failed: %d/n", WSAGetLastError());

WSACleanup();

return 1;

}

//---------------------------------------------

// Create a socket for sending data

SendToSocket =

WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0,

WSA_FLAG_OVERLAPPED);

if (SendToSocket == INVALID_SOCKET) {

fprintf(stderr, "socket failed: %d/n", WSAGetLastError());

WSACloseEvent(Overlapped.hEvent);

WSACleanup();

return 1;

}

//---------------------------------------------

// Set up the RecvAddr structure with the IP address of

// the receiver (in this example case "123.123.123.1")

// and the specified port number.

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_addr.s_addr = inet_addr(targetip);

if (RecvAddr.sin_addr.s_addr == INADDR_NONE) {

fprintf(stderr, "The target ip address entered must be a legal IPv4 address/n");

WSACloseEvent(Overlapped.hEvent);

WSACleanup();

return 1;

}

RecvAddr.sin_port = htons(atoi(targetport));

if(RecvAddr.sin_port == 0) {

fprintf(stderr, "The targetport must be a legal UDP port number/n");

WSACloseEvent(Overlapped.hEvent);

WSACleanup();

return 1;

}

//---------------------------------------------

// Set up the LocalAddr structure with the local IP address

// and the specified port number.

localHost = gethostbyname("");

ip = inet_ntoa(*(struct in_addr *) *localHost->h_addr_list);

LocalAddr.sin_family = AF_INET;

LocalAddr.sin_addr.s_addr = inet_addr(ip);

LocalAddr.sin_port = htons(Port);

//---------------------------------------------

// Bind the sending socket to the LocalAddr structure

// that has the internet address family, local IP address

// and specified port number.

rc = bind(SendToSocket, (struct sockaddr *) &LocalAddr, LocalAddrSize);

if (rc == SOCKET_ERROR) {

fprintf(stderr, "bind failed: %d/n", WSAGetLastError());

WSACloseEvent(Overlapped.hEvent);

closesocket(SendToSocket);

WSACleanup();

return 1;

}

//---------------------------------------------

// Send a datagram to the receiver

printf("Sending datagram from IPv4 address = %s port=%d/n",

inet_ntoa(LocalAddr.sin_addr), ntohs(LocalAddr.sin_port) );

printf(" to IPv4 address = %s port=%d/n",

inet_ntoa(RecvAddr.sin_addr), ntohs(RecvAddr.sin_port) );

// printf("Sending a datagram.../n");

DataBuf.len = BufLen;

DataBuf.buf = SendBuf;

rc = WSASendTo(SendToSocket, &DataBuf, 1,

&BytesSent, Flags, (SOCKADDR *) & RecvAddr,

RecvAddrSize, &Overlapped, NULL);

if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {

fprintf(stderr, "WSASendTo failed: %d/n", err);

WSACloseEvent(Overlapped.hEvent);

closesocket(SendToSocket);

WSACleanup();

return 1;

}

rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);

if (rc == WSA_WAIT_FAILED) {

fprintf(stderr, "WSAWaitForMultipleEvents failed: %d/n",

WSAGetLastError());

retval = 1;

}

rc = WSAGetOverlappedResult(SendToSocket, &Overlapped, &BytesSent,

FALSE, &Flags);

if (rc == FALSE) {

printf("WSASendTo operation failed: %d/n", WSAGetLastError());

retval = 1;

}

else

printf("Number of sent bytes = %d/n", BytesSent);

//---------------------------------------------

// When the application is finished sending, close the socket.

printf("Finished sending. Closing socket./n");

WSACloseEvent(Overlapped.hEvent);

closesocket(SendToSocket);

printf("Exiting./n");

//---------------------------------------------

// Clean up and quit.

WSACleanup();

return (retval);

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics