Win32 网络编程

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;   /* address family, AF_xxx */
    char       sa_data[14]; /* 14 bytes of protocol address */
};

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;    /* Address family */
    unsigned short      sin_port;   /* Port number */
    struct  in_addr     sin_addr;   /* Internet address */   
    char             sin_zero[8];   /* Same size as struct sockaddr */
};

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;  //An IPv4 address formatted as four u_chars.
    struct { u_short s_w1,s_w2; } S_un_w;           //An IPv4 address formatted as two u_shorts
    u_long S_addr;                                  //An IPv4 address formatted as a u_long
    } S_un;
    #define s_addr S_un.S_addr
};
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).


        由于原作者的例子上有少许错误,为此我稍微作了一下修改,废话不多说了,直接上代码,代码已在VS2010下测试通过!

服务器端程序:

           

/************************************************************************************************************
 *Windows Network Programming template, every other network program on windows can be extended 
 *based on this template routine!!!
 *This program creates communication between server terminal and client terminal based on HTTP protocol.
 *Date: August 18,2013
 *************************************************************************************************************/
/*server.c*/
#include
  
  
   
   
#include
   
   
    
    
#pragma comment(lib,"ws2_32.lib")   //This libary must be loaded on windows platform

void main()
{
    WSADATA wsaData;
    SOCKET sockSrv;
    SOCKADDR_IN addrSrv;
    SOCKADDR_IN addrClient;	//recieve the address info of client
    int len=sizeof(SOCKADDR);
    WORD wVersionRequested;	//store the version number of WinSock Lib
    int err;

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

    err=WSAStartup(wVersionRequested,&wsaData);	//load the socket lib
    if(err!=0)	//返回值不等于0,程序退出
    	return ;
    if(LOBYTE(wsaData.wVersion)!=2||
    	HIBYTE(wsaData.wVersion)!=2)	//判断低字节和高字节是否都等于1
    {
    	WSACleanup();	//不等于1,则调用该函数,终止对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变量中,利用这个套接字就可以与客户端通信。
    	                    //先前的套接字仍然继续监听客户端的连接请求

    	//返回连接状态的套接字
    	SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);	//当客户端连接请求到来时,该函数接受该请求,建立连接,同时返回一个新的套接字描述符

    	sprintf_s(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()函数
    }							//终止对套接字库的使用
}
   
   
  
  

客户端程序:

           
/*********************************************************************************************************
 *Windows Network Programming template, every other network program on windows can be extended 
 *based on this template routine!!!
 *This is client terminal network program routine based on HTTP protocal.
 *Date: August 18th,2013
 *****************************************************************************************************/
/*client.cpp*/
#include
   
   
    
    
#include
    
    
     
     

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

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 ;
    }
    SOCKET sockClient=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,"This is zhengfu",strlen("This is zhengfu")+1,0);
    closesocket(sockClient);
    WSACleanup();
}
    
    
   
   

基于UDP协议的网络编程:
服务器端程序:
           
/*****************************************************************************************************
 *This Network Program routine sets up communication between server and client based on UDP protocol
 *every other network program on window can be extended according to this template routine!!!
 *Date:August 18th,2013
 *************************************************************************************************/
/*udp server.cpp*/
/*This program create communications between server and client based on udp protocols*/
/*server.cpp*/
#include
   
   
    
    
#include
    
    
     
     

#pragma comment(lib,"ws2_32.lib")   //This libary must be loaded

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 ;
    }
    SOCKET sockSrv=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("chat end\n");
    		break;
    	}
    	sprintf(tempBuf,"%s say: %s",inet_ntoa(addrClient.sin_addr),recvBuf);
    	printf("%s\n",tempBuf);
    	printf("Please input data:\n");
    	gets(sendBuf);
    	sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);
    }
    closesocket(sockSrv);
    WSACleanup();
}
    
    
   
   


客户端程序:
           
/*********************************************************************************
 *This routine is client program template based on UDP Protocol, 
 *every other client program based on UDP can be extended according to it. 
 *Date: August 18,2013
 **********************************************************************************/
/*UDP client.cpp*/
#include
   
   
    
    
#include
    
    
     
     

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

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 ;
    
    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("please input 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("chat end\n");
    		break;
    	}
    	sprintf(tempBuf,"%s say :%s",inet_ntoa(addrSrv.sin_addr),recvBuf);
    	printf("%s\n",tempBuf);
    }
    closesocket(sockClient);
    WSACleanup();
}

    
    
   
   


       
参考文献:
                 [1]http://blog.csdn.net/ch_jinyi/article/details/7439742
                 [2]百度百科:http://baike.baidu.com/view/2907631.htm

      


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值