Win32 网络编程

来源:互联网 发布:微信js获取signature 编辑:程序博客网 时间:2024/05/23 17:16

1.socket

socket的英文原义是“孔”或“插座”。作为4BDS UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。socket非常类似于电话插座。以一个国家级电话网为例。电话的通话双方相当于相互通信的2个进程,区号是它的网络地址;区内一个单位的交换机相当于一台主机,主机分配给每个用户的局内号码相当于socket号。任何用户在通话之前,首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连接请求(假如对方不在同一区内,还要拨对方区号,相当于给出网络地址)。对方假如在场并空闲(相当于通信的另一主机开机且可以接受连接请求),拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。正如打电话之前,双方必须各自拥有一台电话机一样。在网间网内部,每一个socket用一个半相关描述: (协议,本地地址,本地端口) 一个完整的socket有一个本地唯一的socket号,由操作系统分配。套接字存在于通信区域中,通信区域也叫地址族,主要用于将通过套接字通信的进程的共有特性综合在一起,套接字通常只与同一区域的套接字交换数据。Windows Sockets只支持一个通信区域:网际域(AF_INET),这个域被使用网际协议簇通信的进程使用。TCP/IP协议使用16位整数和32位整数的高位先存格式。

 

2.IP地址:IP网络中每台主机都必须有一个惟一的IP地址,IP地址是一个逻辑地址,因特网上的IP地址具有全球惟一性,32位,4个字节,常用点分十进制格式表示。

 

3.协议:为进行网络中的数据交换(通信)而建立的规则、标准或约定(语义+语法+规则);不同层具有各自不同的协议。

 

4.ISO/OSI(Open System Interconnection)七层参考模型:物理层:提供二进制传输,确定在通信信道上如何传输比特流;数据链路层:提供介质访问,加强物理层的传输功能,建立一条无差错的传输线路;网络层:提供IP寻址和路由,因为在网络上数据可以经由多条线路到达目的地,网络层负责找出最佳的传输线路。传输层:为源端主机到目的端主机提供可靠的数据传输服务,隔离网络的上下层协议,使得网络应用与下层协议无关。会话层:在两个相互通信的应用进程之间建立、组织和协调其相互之间的通信。表示层:处理被传送数据的表示问题,即信息的语法和语义。应用层:为用户的网络应用程序提供网络通信的服务。在两个通信实体进行通信时,应用层所发出的数据经过表示层、会话层、传输层、网络层、数据链路层,最终到达物理层,在该层通过物理线路传输给另一个实体的物理层。然后,数据再依次向上传递,传递给另一个实体的应用层。对等层通信的实质:对等层实体之间虚拟通信,下层向上层提供服务,实际通信在最底层完成。

应用层协议:远程登录协议Telnet.文件传输协议FTP,超文本传输协议HTTP,域名服务DNS,简单邮件传输协议SMTP,邮局协议POP3;传输层协议:TCP:面向连接的可靠的传输协议,利用TCP协议进行通信时,首先要通过三步握手,以建立通信双方的连接。一旦连接建立好,就可以进行通信了。TCP提供了数据确认和数据重传的机制,保证了发送的数据一定能到达通信的对方。UDP:无连接的,不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可以直接向一个IP地址发送数据,但是对方能否收到,无法保证。主要用在一些实时性要求较高的场合。网络层:网际协议IP,Internet互联网控制报文ICMP,Internet组管理协议IGMP

4.TCP/IP:应用层、传输层、网络层和网络接口层。

5.端口:是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序通过系统调用与某端口建立连接后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都通过该端口输出。端口用一个整数型标识符来表示,即端口号。端口使用一个16位的数字来表示,范围是0-65535,1024以下的端口号保留给预定义的服务。

6.客户机/服务器模式:在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式。

7.套接字的类型:流式套接字(SOCK_STREAM)提供面向连接、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收,实际上是基于TCP协议实现的。数据报式套接字(SOCK_DGRAM)提供无连接服务,数据包以独立句形式发送,不提供无错保证,数据可能丢失或重复。并且接收顺序混乱。实际上是基于UDP协议实现。原始套接字(SOCK_RAW)

8.面向TCP的socket编程:服务器端:1.创建套接字,(socket)2.将套接字绑定到一个本地地址和端口上(bind)3.将套接字设为监听模式,准备接收客户请求(listen)4.等待客户请求到来,当请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字。(accept)5.用返回的套接字和客户端进行通信。(send/recv)6.返回,等待另一客户请求7.关闭套接字。

客户端:1.创建套接字(socket)2.向服务器发出连接请求(connect)3.和服务器进行通信(send/recv)4.关闭套接字

9.基于UDP的socket编程:服务器端即先启动的一端为接收端,发送数据的一端为发送端,也称客户端。接收端程序:创建套接字,将套接字绑定到一个本地址和端口上,等待接收数据(recvfrom),关闭套接字。客户端程序:创建套接字,向服务器发送数据(sendto),关闭套接字。

套接字相当于电话机,IP地址相当于总机,端口号相当于分机。

相关函数:1.加载套接字库 int WSAStartup ( WORD

wVersionRequested, LPWSADATA lpWSAData );
wVersionRequested [in] The highest version of Windows Sockets support that thecaller can use. The high order byte specifies the minor version (revision)number(副版本号); thelow-order byte specifies the major version number(主版本号)。lpWSAData [out] A pointer to theWSADATAdata structure that is to receive details of the Windows Socketsimplementation.

typedef struct WSAData {

        WORD                    wVersion;

        WORD                    wHighVersion;

        char                    szDescription[WSADESCRIPTION_LEN+1];

        char                   szSystemStatus[WSASYS_STATUS_LEN+1];

        unsigned short          iMaxSockets;

        unsigned short          iMaxUdpDg;

        char FAR *              lpVendorInfo;

} WSADATA, FAR * LPWSADATA;

An application must call one WSACleanup call for every successfulWSAStartup call to allow third-party DLLs to make use of a WS2_32.DLL on behalfof an application.

2.socket函数:The Windows Sockets socket function creates a socket that is boundto a specific service provider。

SOCKET socket ( int af, inttype, int protocol );

3.bind函数:The Windows Sockets bind function associatesa local address with a socket.

int bind ( SOCKET s, const struct sockaddr FAR* name, int namelen);
s [in] A descriptor identifying an unbound socket. name [in] The address toassign to the socket from theSOCKADDRstructure. namelen [in] The length of the name.

The SOCKADDR structure varies depending on the protocol selected.Except for the sa_family field, SOCKADDR contents are expressed in network byteorder.

struct sockaddr {

        u_short    sa_family;

        char       sa_data[14];

};  

The bind function is used on an unconnected socket before subsequentcalls to theconnectorlistenfunctions. It is used to bind to either connection-oriented (stream) orconnectionless (datagram) sockets. When a socket is created with a call to thesocketfunction, it exists in a name space (address family), but it has no nameassigned to it. Use bind to establish the local association of the socket byassigning a local name to an unnamed socket. sa_data仅仅表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息。由于实际要求的只是内存区,所以对不同的协议家族,用不同的结构来替换sockaddr.。在基于TCP/IP的socket编辑过程中,可以用sockaddr_in结构替换sockaddr。

struct sockaddr_in{

     short            sin_family;

     unsigned short      sin_port;

     struct    in_addr     sin_addr;

     char               sin_zero[8];

};

In the Internet address family, the SOCKADDR_IN structure is used byWindows Sockets to specify a local or remote endpoint address to which toconnect a socket. This is the form of the SOCKADDR structure specific to theInternet address family and can be cast to SOCKADDR. sin_port:要分配给套接字的端口;sin_addr:套接字的主机IP地址。

struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
4.inet_addr:将IP地址指定为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接受数据。若只想让套接字使用多个IP中的一个地址,就必须指定实际地址,可用inet_addr函数实现。

unsigned long inet_addr ( const char FAR * cp );The Windows Socketsinet_addr function converts a string containing an (Ipv4) Internet Protocoldotted address into a proper address for theIN_ADDRstructure.

char FAR * inet_ntoa ( struct in_addr in );The Windows Socketsinet_ntoa function converts an (Ipv4) Internet network address into a string inInternet standard dotted format.返回一个以点分十进制格式表示的IP地址字符串。

5.listen函数:int listen ( SOCKET s, int backlog ); TheWindows Sockets listen function places a socket a state where it is listeningfor an incoming connection.

6.accept函数:SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR*addrlen );The Windows Sockets accept function accepts an incoming connectionattempt on a socket.addr:指向一个缓冲区的指针,该缓冲区用来接收连接实体的地址,就是当客户端向服务器发起连接,服务器接受这个连接时,保存发起连接的这个客户端的IP地址信息和端口信息。

7.send函数
int send ( SOCKET s, const char FAR * buf, int len, int flags);
The Windows Sockets send function sends data on a connected socket.

8.recv函数:int recv (SOCKET s, char FAR* buf, int len, int flags );
The Windows Sockets recv function receives data from a connected socket.

9.connect函数:int connect (SOCKET s,const struct sockaddrFAR* name, int namelen );
The Windows Sockets connect function establishes a connection to a specifedsocket.

10.recvfrom函数:

int recvfrom ( SOCKET s, char FAR* buf,int len,int flags, struct sockaddr FAR* from, int FAR*fromlen );
The Windows Sockets recvfrom function receives a datagram and stores the sourceaddress.

11.sendto函数:int sendto (SOCKET s, const char FAR * buf, int len,int flags,conststructsockaddr FAR * to, int tolen);
The Windows Sockets sendto function sends data to a specific destination.

12.htons htonl函数:u_short htons (u_short hostshort );The Windows Sockets htonsfunction converts a u_short from host to TCP/IP network byte order (which isbig-endian).

u_long htonl ( u_long hostlong);

The Windows Sockets htonl function converts a u_long from host toTCP/IP network byte order (which is big-endian).

服务器端程序:

#include <Winsock2.h>

#include <stdio.h>

 

void main(void)

{   

      WSADATA wsaData;

      SOCKET sockSrv;    

     

      SOCKADDR_IN  addrSrv;

      SOCKADDR_IN addrClient;//用来接受客户端的地址信息

      int len=sizeof(SOCKADDR);

      WORD wVersionRequested;//保存WinSock库的版本号

      int err;  

     

      wVersionRequested =MAKEWORD(2,2);//创建一个包含了请求版本号的WORD值

     

      err =WSAStartup(wVersionRequested, &wsaData);//加载套接字库

      if ( err != 0 ) {//返回值不等于0,程序退出。

           return;

      }

     

      if ( LOBYTE(wsaData.wVersion ) != 2 ||

           HIBYTE(wsaData.wVersion ) != 2 ) {//判断低字节和高字节是否都等于1

           WSACleanup( );//不是的话,调用该函数,终止对Winsock库的使用并返回

           return;

      }

 

      sockSrv=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建套接字

     

      addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

      addrSrv.sin_family=AF_INET;

      addrSrv.sin_port=htons(6000);

      bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//将套接字绑定到本地址和指定的端口号上。

      listen(sockSrv,5);

 

     

     

      while(1)//作为服务器端,需要不断地等待客户端的连接请求的到来,在此设置死循环。

      {

           char recvBuf[100];

           char sendBuf[100];//于当前这个新连接的一个套接字描述符,保存于sockConn变量中,利用这个套接字就可以与客户端通信。先前的套接字仍继续监听客户端的连接请求。

           //返回连接状态的套接字

           SOCKETsockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);//当客户端连接请求到来时,该函数接受该请求,建立连接,同时它将返回一个相对

          

           sprintf(sendBuf,"Welcome%s you",inet_ntoa(addrClient.sin_addr));

           send(sockConn,sendBuf,strlen(sendBuf)+1,0);//用返回的套接字和客户端进行通信。

          

           recv(sockConn,recvBuf,100,0);//从客户端接受数据

           printf("%s\n",recvBuf);

           closesocket(sockConn);//当前通信完成之后,需要调用closesocket函数关闭已建立的套接字,释放为该套接字分配的资源,

      }//然后进入下一个循环,等待另一客户请求的到来。若不是死循环的话,此处还需调用WSACleanup函数终止对套接字库的使用。

}

客户端程序:

#include <Winsock2.h>

#include <stdio.h>

void main()

{

      WORD wVersionRequested;

      WSADATA wsaData;

      int err;

     

      wVersionRequested =MAKEWORD( 1, 1 );

     

      err = WSAStartup( wVersionRequested,&wsaData );

      if ( err != 0 ) {

           return;

      }

     

      if ( LOBYTE(wsaData.wVersion ) != 1 ||

           HIBYTE(wsaData.wVersion ) != 1 ) {

           WSACleanup( );

           return;

      }

      SOCKETsockClient=socket(AF_INET,SOCK_STREAM,0);//将其第三个参数设为0,让其自动选择协议。

      SOCKADDR_IN addrSrv;//设定服务器端的IP和端口

      addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//本地回路地址

      addrSrv.sin_family=AF_INET;

      addrSrv.sin_port=htons(6000);

      connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//与服务器建立连接。

      char recvBuf[100];

      recv(sockClient,recvBuf,100,0);

      printf("%s\n",recvBuf);

      send(sockClient,"Thisis zhangsan",strlen("This is Isir")+1,0);

      closesocket(sockClient);

      WSACleanup();

}

基于UDP的网络编程:

服务器端:

#include <Winsock2.h>

#include <stdio.h>

/* UDP  Server */

void main()

{

      WORD wVersionRequested;

      WSADATA wsaData;

      int err;

     

      wVersionRequested =MAKEWORD(2,2);

     

      err = WSAStartup(wVersionRequested, &wsaData );

      if ( err != 0 ) {

           return;

      }

     

      if ( LOBYTE(wsaData.wVersion ) != 2 ||

           HIBYTE(wsaData.wVersion ) != 2 ) {

           WSACleanup( );

           return;

      }

      SOCKETsockSrv=socket(AF_INET,SOCK_DGRAM,0);

      SOCKADDR_IN addrSrv;

      addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

      addrSrv.sin_family=AF_INET;

      addrSrv.sin_port=htons(6000);

 

      bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

 

      char recvBuf[100];

      char sendBuf[100];

      char tempBuf[200];

 

      SOCKADDR_IN addrClient;

      int len=sizeof(SOCKADDR);

     

      while (1)

      {

           recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);

           if ('q' ==recvBuf[0])

           {

                 sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR *)&addrClient,len);

                 printf("chatend\n");

                 break;

           }

           sprintf(tempBuf,"%ssay:%s",inet_ntoa(addrClient.sin_addr),recvBuf);

           printf("%s\n",tempBuf);

           printf("Pleaseinput data:\n");

           gets(sendBuf);

           sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);

      }

      closesocket(sockSrv);

      WSACleanup();

}
}
客户端:

#include <Winsock2.h>

#include <stdio.h>

void main()

{

      WORD wVersionRequested;

      WSADATA wsaData;

 

      SOCKET sockClient;

      SOCKADDR_IN addrSrv;

      char recvBuf[100];

      char sendBuf[100];

      char tempBuf[200];

     

      int len =sizeof(SOCKADDR);

 

      int err;

     

      wVersionRequested =MAKEWORD(2,2);

     

      err = WSAStartup(wVersionRequested, &wsaData );

      if ( err != 0 ) {

           return;

      }

     

      if ( LOBYTE(wsaData.wVersion ) != 2 ||

           HIBYTE(wsaData.wVersion ) != 2 ) {

           WSACleanup( );

           return;

      }

 

      sockClient =socket(AF_INET,SOCK_DGRAM,0);

     

      addrSrv.sin_addr.S_un.S_addr= inet_addr("127.0.0.1");

      addrSrv.sin_family=AF_INET;

      addrSrv.sin_port=htons(6000);

 

      while (1)

      {

           printf("pleaseinput data:\n");

           gets(sendBuf);

           sendto(sockClient,sendBuf,strlen(sendBuf)+1,0

                 ,(SOCKADDR*)&addrSrv,len);

           recvfrom(sockClient,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len);

 

           if ('q' ==recvBuf[0])

           {

                 sendto(sockClient,"q",strlen("q")+1,0,

                      (SOCKADDR*)&addrSrv,len);

                 printf("chatend;\n");

                 break;

           }

            sprintf(tempBuf,"%s say :%s",inet_ntoa(addrSrv.sin_addr),recvBuf);

           printf("%s\n",tempBuf);

      }

      closesocket(sockClient);

      WSACleanup();

}

P.s.  

 

àALT + F8 :对其文档格式

0 0
原创粉丝点击