Windows套接字编程/Socket

ScoKet套接字编程


1 寻址方式和字节顺序
1.1 寻址方式
  Winsock(Socket API)中,可以使用TCP/IP地址家族中统一的套接字地质结构解决
TCP/IP寻址中可能出现的问题,套接字地址结构定义如下
struct sockaddr_in{
short sin_family;     //地址格式,AF_INET表示TCP/IP
unsigned shory sin_port;//端口号码
struct in_addr sin_addr;//IP地址
char sin_zero[8];       //备用
}

该结构变量sin_addr表示32位的IP地址结构。其结构定义如下

 

struct in_addr{
 union{
	struct{
		unsigned char s_b1,s_b2,s_b3,s_b4;
		}S_un_b;
		struct{
			unsigned short s_w1,s_w2;
			}S_un_w;
			unsigned long S_addr;
			}S_un;
};

1.2 字节顺序
网络字节顺序与主机字节顺序直接的转换函数,如下

 

 

u_short htons(u_short hostshort);//将一个u_short类型的IP地址从主机字节顺序转换到网络字节顺序

u_long htonl(u_long hostlong);//讲一个u_long类型的IP地址从主机字节顺序转换到网络字节顺序

u_long ntohl(u_long netlong);//将一个u_long类型的IP地址从网络字节顺序转换到主机字节顺

u_short ntohs(u_short netshort);//讲一个u_short类型的IP地址从网络字节顺序转换到主机字节顺序

unsigned long inet_addr(const char FAR *cp);//讲一个字符串IP转换到以网络字节顺序排列的IOP地址

char FAR *inet_ntoa(struct in_addr in);//讲一个以网络字节顺序排列的IP地址转换为一个字符串IP

 


2 Socket相关函数
Windows网络程序开发均是基于Windows套接字实现,介绍MFC中的CSocket类函数


2.1创建套接字
CSocket sock;
CSocket *sock;
sock=new CSocket;


2.2绑定地址信息
BOOL Bind(const SOCKADDR* lpSockAddr,int nSockAddrLen);
lpSockAddr指定将要绑定的服务器地址结构
nSockAddrLen表示地址结构的长度


2.3服务器监听客户端连接请求
BOOL Listen(int nConnectionBacklog=5);
nConnectionBacklog表示套接字监听客户端请求的最大数目,有效范围为1-5,表示该套接字最多只能监听
5个客户端所发送的请求。


2.4连接服务器
客户端创建套接字成功后,可以调用函数Connect向服务端发送连接请求
BOOL Connect(const SOCKADDR* lpSockAddr,int nSockAddrLen);


lpSockAddr表示将连接的服务器地址结构
nSockAddrLen表示地址结构的长度大小


2.5数据交换
服务器和客户端都是通过函数Send()和Receive()进行数据交换
virtual int Send(const void* lpBuf,int nBufLen,int nFlags=0);
virtual int Receive(void* lpBuf,int nBufLen,int nFlags=0);


Send()用于发送指定缓冲区的数据,函数Receive()用于接收对方发送的数据,并将数据
存放在指定缓冲区中
参数lpBuf表示数据缓冲区地址
参数nBufLen表示数据缓冲区大小
参数nFlag表示数据发送或接收的标志


2.6关闭套接字对象
sock.Close();




3 Winsock网络程序开发流程
如果在应用程序第二步没有选择项目支持Windows Socket功能,则在程序中手动添加以下头文件
#include


3.1Winsock编程流程
3.1.1 初始化和释放套接字库
所有的Winsock函数均是从动态链接库WS2_32.DLL中导出的,但是VC并没有默认与该库进行连接,所以
在工程设置中,在库模块中添加动态链接库WS2_32.DLL,这样永华就可以调用WinSock函数了。
用户首先须从动态链接库中调用函数WSAStartup()对该库进行初始化,之后才能继续正确调用其他的winSock函数
int WSAStartup(WORD wVersionRequested,LPWSAData);
wVersionRequested表示当前套接字库版本号,lpWSAData指向结构体WSADATA的指针变量


初始化套接字库
WSAData data;
WORD wVersionRequested=MAKEWORD(2,0);
::WSAStartup(wVersionResquested,&data);
当程序退出时,还要调用WSACleanup()释放套接字库
::WSACleanup();


3.1.2 创建套接字句柄
Socket API中,创建套接字句柄函数为scoket().
SOCKET socket(
int af,//指定套接字所用的地址格式,TCP/IP为AF_INET
int type,//套接字类型
int protocol//如果参数type已经指定为套接字类型为TCP或者UDP,则该参数可以设置为0
)
创建流式套接字句柄:
SOCKET s;
s=::socket(AF_INET,SOCK_STREAM,0);


3.1.3绑定地址信息
int bind(
SOCKET s,//套接字句柄
const struct sockaddr FAR* name,//地址结构信息
int namelen//地址结构大小
)


3.1.4 服务器监听
int listen(
SOCKET s,//实现监听功能的套接字句柄
int backlog //指定监听的最大连接数量



3.1.5 客户端连接
int Connect(
SOCKET s,//套接字句柄
const struct sockaddr FAR*name,//将要连接的服务器地址信息结构指针
int namelen//地址信息结构体长度
)


3.1.6 数据收发
int send(SOCKET s,const char FAR *buf,int len,int flags)//发送数据函数
int recv(SOCKET s,char FAR*buf,int len,int flags)//接受数据函数


buf表示指向数据缓冲区的指针变量,参数flag通常设置为0


3.1.7 关闭套接字
int closesocket(
SOCKET s//将关闭的套接字句柄
)

 

 

 

 

 

TCP服务端编程

 

#include//包含头文件
#include
#include
#pragma comment(lib,"WS2_32.lib")//显式连接套接字库
int main()
{
	WSADATA data;//定义WSADATA结构体对象
	WORD w=MAKEWORD(2,0);//定义版本号码
	char sztext[]="欢迎你\r\n";//定义并初始化发送到客户端的字符数组
	::WSAStartup(w,&data);//初始化套接字库
	SOCKET s,s1;//定义连接套接字哭和数据收发套接字句柄
	s=::socket(AF_INET,SOCK_STREAM,0);//创建TCP套接字
	sockaddr_in addr,addr2;//定义套接字地质结构
	int n=sizeof(addr2);//获取套接字地址大小
	addr.sin_family=AF_INET;//初始化套接字结构
	addr.sin_port=htons(75);
	addr.sin_addr.S_un.S_addr=INADDR_ANY;
	::bind(s,(sockaddr*)&addr,sizeof(addr));//绑定套接字
	::listen(s,5);//监听套接字
    printf("服务器已经启动\r\n");//输出提示信息
	while(true)
	{
        s1=::accept(s,(sockaddr*)&addr2,&n);//接受连接请求
		if (s1!=NULL)
		{
			printf("%s 已经连接上\r\n",inet_ntoa(addr2.sin_addr));
			::send(s1,sztext,sizeof(sztext),0);//向客户端发送字符数组
		}
		::closesocket(s);//关闭套接字句柄
		::closesocket(s1);
		::WSACleanup();//释放套接字库
		if (getchar())
		{
			return 0;//正常结束程序

		}
		else
		{
			::Sleep(100);//程序睡眠0.1秒
		}
	}

}

 

 

 

TCP客户端编程

 

#include//包含头文件
#include
#include 
#pragma comment(lib,"WS2_32.lib")//显式连接套接字库
int main()
{
	WSADATA data;//定义WSADATA结构体对象
	WORD w=MAKEWORD(2,0);//定义版本号码
	::WSAStartup(w,&data);//初始化套接字库
	SOCKET s;//定义连接套接字和数据收发套接字句柄
	char sztext[10]={0};
	s=::socket(AF_INET,SOCK_STREAM,0);//创建TCP套接字
	sockaddr_in addr;//定义套接字地址结构
	addr.sin_family=AF_INET;//初始化地址结构
	addr.sin_port=htons(75);
	addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	printf("客户端已经启动\r\n");
	::connect(s,(sockaddr*)&addr,sizeof(addr));//连接服务器端
	::recv(s,sztext,sizeof(sztext),0);//接受信息
	printf("%s\r\n",sztext);
	::closesocket(s);//关闭套接字句柄
	::WSACleanup();//释放套接字库
	if (getchar())//如果有输入,则关闭程序
	{
		return 0;
	}
	else
	{
		::Sleep(100);//程序睡眠0.1秒
	}
}


先运行服务端程序,再运行客户端程序

 

Windows套接字编程/Socket_第1张图片

Windows套接字编程/Socket_第2张图片

Windows套接字编程/Socket_第3张图片
 

如果您觉得这篇博文有用,请访问我的个人站:http://www.stubbornhuang.com,更多博文干货等着您。

你可能感兴趣的:(C++,Socket)