windows网络编程--学习笔记01

 1.Winsock is a standard application programming interface (API) that allows two or more applications (or processes) to communicate either on the same machine or across a network and is primarily designed to foster data communication over a network.
2.Headers and Library that are necessary
When compiling your application with WINSOCK2.H, you should link with WS2_32.LIB library. When using WINSOCK.H (as on Windows CE) you should use WSOCK32.LIB. If you use extension APIs from MSWSOCK.H, you must also link with MSWSOCK.DLL. Once you have included the necessary header files and link environment, you are ready to begin coding your application, which requires initializing Winsock.

3. Initializing Winsock and Free the resources
int WSAStartup(     //加载Winsock库,获取当前Winsock库的相关信息
    WORD wVersionRequested,
    LPWSADATA lpWSAData;
);
typedef struct WSAData 
{
    WORD           wVersion;     //the Winsock version you will be using. 
    WORD           wHighVersion;     //holds the highest version of the Winsock library available. 
    char           szDescription[WSADESCRIPTION_LEN + 1]; //*
    char           szSystemStatus[WSASYS_STATUS_LEN + 1];     //*这两个都木有用滴
    unsigned short iMaxSockets;     //*同时打开的最大连接数
    unsigned short iMaxUdpDg;     //*数据包的最大长度。both depends on the physical resources
    char FAR *     lpVendorInfo;
} WSADATA, * LPWSADATA; 
When your application is completely finished using the Winsock interface, you should call WSACleanup, which allows Winsock to free up any resources allocated by Winsock and cancel any pending Winsock calls that your application made. WSACleanup is defined as
int WSACleanup(void);

4.SOCKADDR_IN structure     //存储寻址信息的结构体

In Winsock, applications specify IP addresses and service port information through the SOCKADDR_IN structure, which is defined as

struct sockaddr_in
{
    short           sin_family;     // ip地址簇,The sin_family field must be set to AF_INET(IPv4), which tells Winsock we are using the IP address family
    u_short         sin_port;     // 端口号(网络字节序),defines which TCP or UDP communication port will be used to identify a server service.      
    struct in_addr  sin_addr;     //ip地址(网络字节序),ip address
    char            sin_zero[8];     // 只作为填充用途,使SOCKADDR_IN结构与in_addr结构一样大小(两者可互相转换)
}

A useful support function named inet_addr converts a dotted IP address to a 32-bit unsigned long integer quantity. The inet_addr function is defined as

//以下的函数将字符串形式的ip地址转换为网络地址序的32位无符号长整数形式(填充SOCKADDR_in结构的in_addr结构式要用到)
unsigned long inet_addr(
    const char FAR *cp      //cp为一个以NULL终止的字符串(如"11.11.11.11")
); 

The cp field is a null-terminated character string that accepts an IP address in dotted notation. Note that this function returns an IP address as a 32-bit unsigned long integer in network-byte order.


5.ByteOrdering Conversion Between Host and Network(主机字节顺序和网路字节顺序的转换)

//Host to Network(4 functions)
u_long htonl(u_long hostlong);

int WSAHtonl(
    SOCKET s,
    u_long hostlong,
    u_long FAR * lpnetlong
);

u_short htons(u_short hostshort);

int WSAHtons(
    SOCKET s,
    u_short hostshort,
    u_short FAR * lpnetshort
);

// Network to Host(also 4 functions)
u_long ntohl(u_long netlong);

int WSANtohl(
    SOCKET s,
    u_long netlong,
    u_long FAR * lphostlong
);

u_short ntohs(u_short netshort);

int WSANtohs(
    SOCKET s,
    u_short netshort,
    u_short FAR * lphostshort
);

6. A simple instance (寻址案例)

We will now demonstrate how to address IPv4 by creating a SOCKADDR_IN structure using the inet_addr and htons functions described previously.

SOCKADDR_IN InternetAddr;
INT nPortId = 5150;

InternetAddr.sin_family = AF_INET;

// Convert the proposed dotted Internet address 136.149.3.29
// to a four-byte integer, and assign it to sin_addr

InternetAddr.sin_addr.s_addr = inet_addr("136.149.3.29");

// The nPortId variable is stored in host-byte order. Convert
// nPortId to network-byte order, and assign it to sin_port.

InternetAddr.sin_port = htons(nPortId);

7.Connection-Oriented Communication
  • 创建一个套接字
SOCKET socket (
    int af,     //ip地址簇, AF_INET为IPv4
    int type,     //该套接字所用的协议,TCP/IP为SOCK_STREAM,UDP/IP为SOCK_DGRAM
    int protocol     //用于对具体的传送做限定,TCP为IPPROTO_TCP,UDP为UPPROTO_UDP
);
  • 将套接字与ip地址和端口绑定
int bind(
    SOCKET                     s,      //要绑定的套接字
    const struct sockaddr FAR* name,     //要绑定的ip地址
    int                        namelen     //上一参数,SOCKADDR_IN的大小
);
一旦出错,bind()返回SOCKET_ERROR
  • 监听
int listen(
    SOCKET s, 
    int    backlog     //挂起请求队列的最大长度(即允许最多有多少个请求在等待)
);
  • 接受连接
SOCKET accept(
    SOCKET s,      //被绑定的套接字,它处于监听模式
    struct sockaddr FAR* addr,  //accept()返回后,addr结构会包含发出连接请求的那个客户机的IPv4地址信息
    int FAR* addrlen     //上一参数addr结构的长度的指针
)     //正因为addr和addrlen是函数返回后才带回来的,所以要用指针带回来
  • 发送数据
int send(
    SOCKET s,    //已建立连接,将用于发送数据的套接字
    const char FAR * buf,      //指向要发送的数据的缓冲区的指针
    int len, //即将发送缓冲区内的字符数
    int flags     //可为0,MSD_DONTROUTE或MSG_OOB,其中MSG_DONTROUTE标志要求
传输层不要路由它的数据包,MSG_OOB代表要对发送的数据进行带外发送,特别重要的数据才会用此标记
);
正常情况下send()返回发送的字节数,若发生错误,则返回SOCKET_ERROR.
 
             

The Winsock 2 version of the send API function, WSASend, is defined as

int WSASend(
    SOCKET s,
    LPWSABUF lpBuffers,     //指向一个或多个WSABUF结构的指针
   DWORD dwBufferCount,     //WSABUF结构的个数
    LPDWORD lpNumberOfBytesSent,     //函数返回时带回来的,代表发送了多少字节的数据
    DWORD dwFlags,     //同send()中的flag
    LPWSAOVERLAPPED lpOverlapped,
    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
  • 接受数据
    int recv(
        SOCKET s, 
        char FAR* buf, 
        int len, 
        int flags
    );
    
    int WSARecv(
        SOCKET s, 
        LPWSABUF lpBuffers, 
        DWORD dwBufferCount, 
        LPDWORD lpNumberOfBytesRecvd, 
        LPDWORD lpFlags, 
        LPWSAOVERLAPPED lpOverlapped, 
        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    );
    
控制套接字属性的几个函数:setsockopt, getsockopt, ioctlsocket, and WSAIoctl.
 
服务器和客户端建立连接的几个必须步骤如下:


确保要发送的数据的完整性

sent:

char sendbuff[2048];
int  nBytes = 2048,
     nLeft,
     idx;

// Fill sendbuff with 2048 bytes of data

// Assume s is a valid, connected stream socket
nLeft = nBytes;
idx = 0;

while (nLeft > 0)
{
    ret = send(s, &sendbuff[idx], nLeft, 0);
    if (ret == SOCKET_ERROR)
    {
        // Error
    }
    nLeft -= ret;
    idx += ret;
}
 
          
receive:
char    recvbuff[1024];
int     ret,
        nLeft,
        idx;

nLeft = 512;
idx = 0;

while (nLeft > 0)
{
    ret = recv(s, &recvbuff[idx], nLeft, 0);
    if (ret == SOCKET_ERROR)
    {
        // Error
    }
    idx += ret;
    nLeft -= ret;
}
 
           
To ensure that all data an application sends is received by the peer, a well-written application should notify the receiver that no more data is to be sent. Likewise, the peer should do the same. This is known as a graceful close and is performed by the shutdown function, defined as
int shutdown(
    SOCKET s, 
    int how
);

8.How to construct a server that can receive a client connection(A sample)
#include <winsock2.h>

void main(void)
{
   WSADATA              wsaData;
   SOCKET               ListeningSocket;
   SOCKET               NewConnection;
   SOCKADDR_IN          ServerAddr;
   SOCKADDR_IN          ClientAddr;
   int                  Port = 5150;
   
   // Initialize Winsock version 2.2

   WSAStartup(MAKEWORD(2,2), &wsaData);
   
      // Create a new socket to listen for client connections.
 
      ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
       
      // Set up a SOCKADDR_IN structure that will tell bind that we
      // want to listen for connections on all interfaces using port
      // 5150. Notice how we convert the Port variable from host byte
      // order to network byte order.
       
      ServerAddr.sin_family = AF_INET;
      ServerAddr.sin_port = htons(Port);    
      ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
       
      // Associate the address information with the socket using bind.
       
      bind(ListeningSocket, (SOCKADDR *)&ServerAddr, 
      sizeof(ServerAddr));

   // Listen for client connections. We used a backlog of 5, which
   // is normal for many applications.

      listen(ListeningSocket, 5); 

   // Accept a new connection when one arrives.

      NewConnection = accept(ListeningSocket, (SOCKADDR *) 
                          &ClientAddr,&ClientAddrLen));

   // At this point you can do two things with these sockets. Wait
   // for more connections by calling accept again on ListeningSocket
   // and start sending or receiving data on NewConnection. We will
   // describe how to send and receive data later in the chapter.

   // When you are finished sending and receiving data on the
   // NewConnection socket and are finished accepting new connections
   // on ListeningSocket, you should close the sockets using the
   // closesocket API. We will describe socket closure later in the 
   // chapter.

      closesocket(NewConnection);
      closesocket(ListeningSocket);

   // When your application is finished handling the connections, 
   // call WSACleanup.

      WSACleanup();
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值