网络编程 C++ ———WinSock

网络编程 C++ ———WinSock


                Windows Socket (即Winsock)以U.C. Berkeley大学BSD UNIX中流行的Socket接口为范例定义了一套microsoft Windows下网络编程接口。它不仅包含了人们所熟悉的Berkeley Socket风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。
            通信的基础是套接口(Socket),一个套接口是通讯的一端。包含5种信息:
  •  本地协议端口
  •  本地主机地址
  •  远程协议端口
  •  远程主机地址
  •  协议 (程序在网络上传输数据是使用的协议)
        套接字分类:
  •    流式套接字 (SOCK_STREAM)         
             提供了双向、有序的、无重复的以及无记录边界的数据流服务,适合处理大量数据。它是面向联结的,必须建立数据传输链路,同时还必须对传输的数据进行验证,     确保数据的准确性。因此,系统开销较大。
  •    数据报套接字 (SOCK_DGRAM)         
          数据报套接字也支持双向的数据流,但不保证传输数据的准确性,但保留了记录边界。由于数据报套接字是无联接的,例如广播时的联接,所以并不保证接收端是否正在侦听。数据报套接字传输效率比较高。
  •    原始套接字   (SOCK_RAW)                
         原始套接字保存了数据包中的完整IP头,前面两种套接字只能收到用户数据。因此可以通过原始套接字对数据进行分析。支持更底层的协议 ,多用于实验新的协议和抓包嗅探。
  
         套接字结构体:  
struct sockaddr {
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes of direct address */
};
      该结构体地址为通用Socket地址结构 。sa_family 可以选择不同的通信域。 下面的sockaddr_in则是专门针对Internet域的Socket地址结构体。
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;
    
          主机地址结构体:
struct hostent {
char FAR * h_name; /* official name of host */
char FAR * FAR * h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr h_addr_list[0] /* address, for backward compat */
};
h_name为主机名字。
h_aliases为主机别名列表。
h_addrtype为地址类型。
h_length为地址类型。
h_addr_list为IP地址,如果该主机有多个网卡,就包括地址的列表。

数据类型的基本定义:
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;

几个常用的字节(网络 与主机)转换函数: 
unsigned long inet_addr(const char FAR * cp )
用法: unsigned long addr=inet_addr("192.1.8.84")
u_short ntohs(u_short nPort )     network to host short 
u_short htons(u_short nPort )
u_long htonl(u_long  nAddr)
u_long ntohl(u_long  nAddr)

WinSock 编程需要包含头文件Winsock2.0 和库文件WS2_32.LIB 和动态库WS2_32.DLL。在使用其库函数之前必须加载套接字库。
int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );wVersionRequested
   wVersionRequested:一个WORD(双字节)型数值,指定了应用程序需要使用的Winsock规范的最高版本。
  lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节。
在应用程序关闭套接字之后,应该调用WSACleanUp()终止Winsock DLL的调用,释放资源,以备下一次使用。


Winsock API

SOCKET socket(int af,int  type,int protocol)
int bind( SOCKET s, const struct sockaddr FAR * name, int namelen )
int listen(SOCKET s, int backlog )
SOCKET accept( SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen )
int connect(SOCKET s, const struct sockaddr FAR * name, int namelen )
int send(SOCKET s, const char FAR * buf, int len, int flags )
int recv( SOCKET s, char FAR * buf, int len, int flags )
int shutdown(SOCKET s, int how)
int closesocket( SOCKET s )


int getsockopt(SOCKET s, int level, int optname, char FAR * optval, int FAR * optlen)
读取socket属性,s为欲读取属性的套接字。level为套接字选项的级别,大多数是特定协议和套接字专有的。如IP协议应为 IPPROTO_IP。
optname为读取选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度
用法:
int ttl=0; //读取TTL值
int rc = getsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));

int setsockopt(SOCKET s,int level, int optname,const char FAR * optval, int optlen)
设置socket属性,s为欲设置属性的套接字。
level为套接字选项的级别,用法同上。
optname为设置选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度
用法:
int ttl=32; //设置TTL值
int rc = setsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));

流式套接字编程模型:


数据报套接字编程模型:
        

WinSock的TCP通信 例子程序(VC++6.0 实现):
//TCPSrv
#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib,"WS2_32.lib")

int InitSock(BYTE minorVer=2,BYTE majorVer=2)
  {
	  WSADATA wsadata;
	  WORD sockVersion=MAKEWORD(minorVer,majorVer);
	  if(::WSAStartup(sockVersion,&wsadata)!=0)
	  {   
		  printf("failed WSAStarUp() ");
		  return 0;
	  }
	  return 1;
  }

void UnInitSock()
{
	::WSACleanup();
}

int main()
{
    if(!InitSock())
		return 0;
	SOCKET sListen=::socket (AF_INET,SOCK_STREAM,IPPROTO_IP);
	if(sListen==INVALID_SOCKET)
	{
		printf("failed socket()");
		return 0;
	}
// 填充地址结构体
	sockaddr_in sAddr;
	sAddr.sin_family=AF_INET;
	sAddr.sin_port=htons(7565);
	sAddr.sin_addr.S_un.S_addr=INADDR_ANY;

	if(::bind (sListen,(LPSOCKADDR)&sAddr,sizeof(sAddr))==SOCKET_ERROR)
	{
		printf("failed bind()");
		return 0;
	}

	if(::listen (sListen,2)==SOCKET_ERROR)
	{
		printf("failed listen()");
		return 0;
	}

	sockaddr_in cAddr;
	int nAddrLen=sizeof(cAddr);
	SOCKET sClient;
	char szText[]="TCP Server Demo! \r\n";
	while(TRUE)
	{
		sClient=::accept(sListen,(SOCKADDR*)&cAddr,&nAddrLen);
		if(sClient==INVALID_SOCKET)
		{
			printf("failed accpet()");			
	     	continue;
		}
		printf("½ÓÊÕµ½Ò»¸öÁ¬½Ó£º%s \r\n",inet_ntoa(cAddr.sin_addr));

		::send(sClient,szText,strlen(szText),0);
		::closesocket(sClient);
	}

	::closesocket(sListen);
	UnInitSock();
	return 0;
}


//TCPClient

#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib,"WS2_32.lib")

int InitSock(BYTE minorVer=2,BYTE majorVer=2)
  {
	  WSADATA wsadata;
	  WORD sockVersion=MAKEWORD(minorVer,majorVer);
	  if(::WSAStartup(sockVersion,&wsadata)!=0)
	  {   
		  printf("failed WSAStarUp() ");
		  return 0;
	  }
	  return 1;
  }

void UnInitSock()
{
	::WSACleanup();
}

int main()
{
    if(!InitSock())
		return 0;
		SOCKET s=::socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(s==INVALID_SOCKET)
	{
		printf("failed socket()");
		return 0;
	}
 
	sockaddr_in servAddr;
        servAddr.sin_family=AF_INET;
	servAddr.sin_port=htons(7565);
	servAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); //ÔÚ±¾»ú²âÊÔ £¬ÔÚÁ½Ì¨²»Í¬»úÆ÷ÔÚʹÓÃÏìÓ¦µÄIpµØÖ·¼´¿É

	if(::connect(s,(sockaddr*)&servAddr,sizeof(servAddr))==-1)
	{
		printf("failed connect()");
		return 0;
	}

	char buff[256];
	int nRecv=::recv(s,buff,256,0);
	if(nRecv>0)
	{
		buff[nRecv]='\0';
		printf("接收到数据%s",buff);
	}
	::closesocket(s);
	UnInitSock();
	return 0;
}




                           


 



 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值