代码改变世界

Winsock网络编程

2015-09-05 19:46  rangers  阅读(544)  评论(0编辑  收藏  举报

Winsock是Windows下网络编程的标准接口。使用Winsock编程的步骤一般是比较固定的。

首先要包含头文件#include <WinSock2.h>,同时要添加WS2_32.lib的链接:

#include <WinSock2.h>

#pragma comment(lib,"WS2_32") 

每个 Winsock 应用程序必须加载相应版本的 Winsock DLL,一般通过WSAStartup函数实现,这个函数有两个功能,一是加载套接字库,二是进行套接字库的版本协商,也就是确定要使用的winsock版本。
函数原型如下:

int WSAAPI WSAStartup( __in WORD wVersionRequested,__out LPWSADATA lpWSAData );

每一个对 WSAStartup 的调用必须对应一个对 WSACleanup 的调用,这个函数释放
Winsock 库。

int WSAAPI WSACleanup( void );  

下面通过一些简单的例子来说明winsock编程的流程:

基于TCP(面向连接)的socket编程

基于TCP的socket编程服务端程序流程如下:

  • 创建套接字(socket)
  • 绑定套接字到指定的IP和端口号(bind)
  • 设置套接字进入监听状态(listen)
  • 等待客户连接请求(accept)
  • 收发数据,进行通信(send/recv)
  • 关闭套接字

基于TCP的socket编程客户端程序流程如下:

  • 创建套接字(socket)
  • 向服务器发出连接请求(connect)
  • 和服务端进行通信(send/recv)
  • 关闭套接字

//基于TCP的服务端程序

#include <WinSock2.h>
#include <iostream>
#include <string>
#pragma comment(lib,"WS2_32")

using std::cout;
using std::endl;
using std::string;

//服务器端程序
void TcpServer()
{
	//加载winsock库
	WSADATA wsaData;
	WORD socktVersion = MAKEWORD(2,2);	//版本号
	if (0 != ::WSAStartup(socktVersion,&wsaData))  //加载套接字库
	{
		return;
	}

	//1、创建服务器端套接字
	SOCKET serverSocket = ::socket(AF_INET,SOCK_STREAM,0); //使用TCP连接

	//2、绑定套接字到指定IP和端口
	sockaddr_in server_address;
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(6000);	//指定端口号
	server_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //指定IP地址
	::bind(serverSocket,(LPSOCKADDR)&server_address,sizeof(server_address)); //绑定IP地址与端口号

	//3、设置套接字为监听状态
	::listen(serverSocket,5);//

	char sendmsg[] = "TCP Server Say Hello!";
	//4、等待客户端连接
	cout << "\nWait For Connect...";
	while (true)
	{
		SOCKET client_socket;
		sockaddr_in client_address;
		int address_len = sizeof(client_address);
		client_socket = ::accept(serverSocket,(LPSOCKADDR)&client_address,&address_len); //等待连接
		if (client_socket == INVALID_SOCKET)
		{
			cout << "\nFailed Accept!";
			break;
		}
		char *str_adress = inet_ntoa(client_address.sin_addr);
		cout << "\nA client connected.   IP:" << str_adress;

		//5、收发数据
		::send(client_socket,sendmsg,strlen(sendmsg),0);

		::closesocket(client_socket);//关闭连接
	}


	//6、关闭服务端socket
	::closesocket(serverSocket);
	::WSACleanup();	//释放winsock库
}

客户端程序:

#include <WinSock2.h>
#include <iostream>
#include <string>

#pragma comment(lib,"WS2_32")

using std::cout;
using std::endl;
using std::string;


void TCPClient()
{
	//加载winsock库
	WSADATA wsaData;
	WORD socktVersion = MAKEWORD(2,2);	//版本号
	if (0 != ::WSAStartup(socktVersion,&wsaData))  //加载套接字库
	{
		return;
	}

	//1.建立socket
	SOCKET clientSocket = ::socket(AF_INET,SOCK_STREAM,0); //使用TCP连接
	//填写服务器地址
	sockaddr_in server_address;
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(6000);	//连接端口号
	server_address.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //服务器IP地址

	//2、发出连接请求
	if (-1 == ::connect(clientSocket,(LPSOCKADDR)&server_address,sizeof(server_address)))
	{
		cout << "\nConnect Server Failed!";
		return;
	}

	cout << "\nConnected to server...";
	//3、收发数据
	char rev_buf[1024] = {0};
	::recv(clientSocket,rev_buf,1024,0);
	cout << "\nReceive server msg: " << rev_buf;
	//4、关闭连接
	::closesocket(clientSocket);
	::WSACleanup();	//释放winsock库
}

运行如下:
tcp_png

基于UDP(面向无连接)的socket编程

服务端程序流程如下:

  • 创建套接字(socket)
  • 绑定套接字到指定的IP和端口号(bind)
  • 等待接收数据(recvfrom)
  • 关闭套接字

客户端程序流程如下:

  • 创建套接字(socket)
  • 向服务端发送数据(sendto)
  • 关闭套接字

基于UDP的服务端程序,接收客户端发送的数据,并输出

void UdpServer()
{
	//加载winsock库
	WSADATA wsaData;
	WORD socktVersion = MAKEWORD(2,2);	//版本号
	if (0 != ::WSAStartup(socktVersion,&wsaData))  //加载套接字库
	{
		return ;
	}

	//1.建立socket
	SOCKET serverSocket = ::socket(AF_INET,SOCK_DGRAM,0); //使用UDP协议
	//填写地址
	sockaddr_in server_address;
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(6000);	//连接端口号
	server_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //服务器IP地址

	//2、绑定套接字
	::bind(serverSocket,(LPSOCKADDR)&server_address,sizeof(server_address)); //绑定IP地址与端口号

	//3、接收数据
	char recv_buf[1024] = {0};
	sockaddr_in client_address;
	int address_len = sizeof(client_address);
	while (true)
	{
		//接收数据
		int recv_cnt = ::recvfrom(serverSocket,recv_buf,1024,0,(sockaddr*)&client_address,&address_len);
		if (recv_cnt > 0)
		{
			recv_buf[recv_cnt] = '\0';
			cout << "\nReceive Data From " << inet_ntoa(client_address.sin_addr) << " : " << recv_buf;
		}
	}
	//3、关闭连接
	::closesocket(serverSocket);
	::WSACleanup();	//释放winsock库
}

客户端程序:

void UdpClient()
{
	//加载winsock库
	WSADATA wsaData;
	WORD socktVersion = MAKEWORD(2,2);	//版本号
	if (0 != ::WSAStartup(socktVersion,&wsaData))  //加载套接字库
	{
		return ;
	}

	//1.建立socket
	SOCKET clientSocket = ::socket(AF_INET,SOCK_DGRAM,0); //使用UDP协议
	//填写服务器地址
	sockaddr_in server_address;
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(6000);	//连接端口号
	server_address.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //服务器IP地址

	//2、收发数据
	char send_buf[1024] = {0};
	string input_str;
	bool is_finished = false;
	while (!is_finished)
	{
		cout << "Input Send Msg: ";
		std::getline(std::cin,input_str);
		if (input_str.empty())
		{
			continue;
		}
		if ("exit" == input_str)
		{
			is_finished = true;
			continue;
		}
		sprintf_s(send_buf,1024,"%s",input_str.c_str());
		::sendto(clientSocket,send_buf,strlen(send_buf),0,(sockaddr*)&server_address,sizeof(server_address)); //发送数据
	}
	//3、关闭连接
	::closesocket(clientSocket);
	::WSACleanup();	//释放winsock库
}