网络-WinSocket-socket编程

在windows平台下进行socket编程,其实有一些步骤是固定不变的,只要遵循这些流程就不会被那些繁琐的网络API、数据结构弄晕。

完整的服务器端和客户端源代码,可以去这里下载(点击打开链接)。


这里就以WinSocket中的TCP通信为例,编写一个客户端,向服务器发送一个消息,编写一个服务器端,向客户端反射一个消息,以此对详细的编程步骤进行说明。

一、服务器端

1、首先配置好WinSocket编程环境,如引用头文件、链接静态库等

#include <WinSock2.h>

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

2、初始化WinSocket库

// 协商套接字版本信息,初始化套接字库
	WSADATA wsaData;
	int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0)
	{
		printf("WSAStartup failed with error: %d", iResult);
		return 1;
	}

3、创建用于监听客户端连接请求的socket,注意此socket并不用于进行数据传输

// 创建用于监听的套接字
	SOCKET ServSocket = INVALID_SOCKET;
	ServSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (ServSocket == INVALID_SOCKET)
	{
		printf("socket failed with error: %d", WSAGetLastError());
		WSACleanup();
		return 1;
	}

4、指定监听socket的地址和端口号,客户端便可以连接到该socket

// 为监听套接字绑定地址和端口号
	SOCKADDR_IN addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_addr.S_un.S_addr = INADDR_ANY;
	addrServ.sin_port = htons(DEFAULT_PORT);
	iResult = bind(ServSocket, (SOCKADDR*)&addrServ, sizeof(SOCKADDR_IN));
	if (iResult == SOCKET_ERROR)
	{
		printf("bind faield with error: %d\n", WSAGetLastError());
		closesocket(ServSocket);
		WSACleanup();
		return 1;
	}

5、将监听socket设置为监听状态

// 开启监听状态
	iResult = listen(ServSocket, SOMAXCONN);
	if (iResult == SOCKET_ERROR)
	{
		printf("listen faield with error: %d\n", WSAGetLastError());
		closesocket(ServSocket);
		WSACleanup();
		return 1;
	}
	printf("server is listening ......\n");

6、接收客户端发来的连接请求,并保存用于标识客户端的已连接socket,以便后面能利用该socket与该客户端进行通信,这一步默认情况下会阻塞主线程

// 接收客户端的链接请求,并且返回已连接套接字,负责与本次连接的客户端通信
		SOCKET AcceSocket = INVALID_SOCKET;
		SOCKADDR_IN addrClient;
		int addrClienLen = sizeof(SOCKADDR_IN);
		AcceSocket = accept(ServSocket, (SOCKADDR*)&addrClient, &addrClienLen);
		if (AcceSocket == INVALID_SOCKET)
		{
			printf("accept failed with error: %d\n", WSAGetLastError());
			break;
		}
		printf("a cilent has connect successful, its ip: %s\n", inet_ntoa(addrClient.sin_addr));

7、利用已连接socket接收客户端发送的消息,这一步默认情况下也会阻塞主线程

// 接收客户端发送的数据
		char recvBuf[DEFAULT_BUF_LEN];
		memset(recvBuf, 0, sizeof(recvBuf));
		iResult = recv(AcceSocket, recvBuf, DEFAULT_BUF_LEN, 0);
		// 成功接收到数据
		if (iResult > 0)
		{
			printf("%d bytes data received: ", iResult);
			printf("%s\n", recvBuf);
			closesocket(AcceSocket);
		}
		// 连接关闭
		else if (iResult == 0)
		{
			printf("current connection closing\n");
			closesocket(AcceSocket);
		}
		// 接收发生错误
		else
		{
			printf("recv failed with error: %d\n", WSAGetLastError());
			closesocket(AcceSocket);
			break;
		}

8、利用已连接socket向客户端回射一个消息,发送操作默认也会阻塞

// 回射一个消息
			char sendBuf[DEFAULT_BUF_LEN] = "this is server";
			iResult = send(AcceSocket, sendBuf, strlen(sendBuf), 0);
			if (iResult == SOCKET_ERROR)
			{
				printf("send faield with error: %d\n", WSAGetLastError());
				closesocket(AcceSocket);
			}

二、客户端

相比服务器端的编程步骤,客户端的创建少了对监听socket的操作,多了对服务器端地址的解析,以及发起连接请求的操作。

第1、2步的引入环境、初始化库同服务器端

3、根据输入的服务器端地址,解析出其ip地址,用于进行正常通信

// 解析服务器地址信息
	char pstrHost[512];
	printf("please input a host: ");
	scanf("%s", pstrHost);
	LPHOSTENT lpHost = gethostbyname(pstrHost);
	if (lpHost == NULL)
	{
		printf("host not found\n");
		WSACleanup();
		return 1;
	}

	// 获得目的ip地址
	SOCKADDR_IN addrDest;
	addrDest.sin_family = AF_INET;
	addrDest.sin_addr.S_un.S_addr = *((ULONG*)(lpHost->h_addr_list[0]));
	addrDest.sin_port = htons(DEFAULT_PORT);

4、创建客户端socket,用于与服务器端进行通信

// 创建客户端套接字,用于连接和通信
	SOCKET ConnecSocket = INVALID_SOCKET;
	ConnecSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (ConnecSocket == INVALID_SOCKET)
	{
		printf("socket failed with error: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

5、向服务器端发起连接请求,建立通信连接

// 向服务器发起连接请求
	iResult = connect(ConnecSocket, (SOCKADDR*)&addrDest, sizeof(SOCKADDR_IN));
	if (iResult == SOCKET_ERROR)
	{
		printf("connect faield with error: %d\n", WSAGetLastError());
		closesocket(ConnecSocket);
		WSACleanup();
		return 1;
	}

第5、6步的发送和接收消息同服务器端的第7、8步


最终的服务器端、客户端的运行效果如下:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值