基于TCP的简单socket通信

前两天开始翻看UNIX网络编程,看到了一个基于TCP的socket通信实例(客户端向服务器请求当前时间),于是自己在vs上实现了下,以加深对socket通信流程的了解,代码如下:

 

客户端

#include <windows.h>
#include <iostream>
#include <cassert>
#include <io.h>
#include "../../Server/Server/SocketUtil.h"

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

const int ServerPort = 2013;
const char* pServerIP = "127.0.0.1";

int main()
{
	//初始化winsock
	WSAData wsaData;
	memset(&wsaData, NULL, sizeof(WSAData));
	if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
	{
		RecordError("init winsock failed");
		return 0;
	}

	SocketHolder sholder;
	//创建socket
	int sockFd = 0;
	if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		RecordError("socket create error");
		return 0;
	}
	
	sholder.SetSocketFd(sockFd);
	//初始化socket地址
	sockaddr_in servAddr;
	//sockaddr_in最后8个字节用于占位,为了与sockaddr大小一致
	memset(&servAddr, NULL, sizeof(sockaddr_in));
	servAddr.sin_family = AF_INET;
	/*
	* htons将host字节序排列的数转化为network字节序排列的short类型(端口号是16位的)
	* ServerPort=13,在本地按主机字节序存储为(按16位)0000 0000 0000 1101,
	* 转化为网络字节序为0000 1101 0000 0000,为3328
	*/
	servAddr.sin_port = htons(ServerPort);
	assert(pServerIP);
	/*
	* inet_pton将标准文本形式的IP地址转化为数字二进制形式
	* server ip为127.0.0.1
	* s_addr=1<<24 + 127=16777343,IP地址为32位
	*/
	servAddr.sin_addr.s_addr = inet_addr(pServerIP);

	//请求连接服务器
	std::cout<<"start connect ..."<<std::endl;
	if (connect(sockFd, (sockaddr*)(&servAddr), sizeof(servAddr)) < 0)
	{
		//10061:服务器拒绝连接 10060:连接超时
		RecordError("connect failed");
		return 0;
	}

	std::cout<<"host sockfd = "<<sockFd<<std::endl;
	PrintClientConnectInfo(servAddr);
	std::cout<<std::endl;
	std::cout<<"connect successed"<<std::endl;
	int nCount = 0;
	char buf[MAX_PATH] = {0};
	while ((nCount = recv(sockFd, buf, sizeof(buf), 0)) > 0)
	{
		std::cout<<buf;
		memset(buf, NULL, sizeof(buf));
	}
	return 0;
}


 

服务器端

#include <Windows.h>
#include <ctime>
#include <iostream>
#include <io.h>
#include "SocketUtil.h"

#pragma comment(lib, "Ws2_32.lib")
const int ServerPort = 2013;


int main ()
{
	WSAData wsaData;
	memset(&wsaData, NULL, sizeof(WSAData));
	if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
	{
		RecordError("init winsock failed");
		return 0;
	}

	SocketHolder sholder;

	int nListeningSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (nListeningSocket < 0)
	{
		RecordError("listening socket create error");
		return 0;
	}

	sholder.SetSocketFd(nListeningSocket);

	sockaddr_in serverAddr;
	memset(&serverAddr, NULL, sizeof(sockaddr_in));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(ServerPort);
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	int nBindResult = bind(nListeningSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
	if (nBindResult != 0)
	{
		RecordError("server bind failed");
		return 0;
	}

	int nListeningResult = listen(nListeningSocket, 5);
	if (nListeningResult != 0)
	{
		RecordError("listen failed");
		return 0;
	}

	int nConnectedSock = INVALID_SOCKET;
	time_t t = 0;
	char timeBuf[MAX_PATH] = {0};

	std::cout<<"start server ..."<<std::endl;
	while (true)
	{
		nConnectedSock = accept(nListeningSocket, (sockaddr*)NULL, NULL);
		if (nConnectedSock == INVALID_SOCKET)
		{
			RecordError("accept failed");
			continue;
		}

		sockaddr_in clientAddr;
		memset(&clientAddr, NULL, sizeof(clientAddr));
		int nSize = sizeof(clientAddr);
		getpeername(nConnectedSock,(sockaddr *)&clientAddr,&nSize);  

		std::cout<<"receive a request sockfd = "<<nConnectedSock<<" ";
		PrintClientConnectInfo(clientAddr);
		std::cout<<std::endl;

		t = time(NULL);
		sprintf_s(timeBuf, sizeof(timeBuf), "%.24s\r\n", ctime(&t));
		//write(nConnectedSock, timeBuf, strlen(timeBuf));
		send(nConnectedSock, timeBuf, strlen(timeBuf), 0);
		closesocket(nConnectedSock);
	}
	std::cout<<"stop server ..."<<std::endl;
	return 0;
}


工具

#pragma once

void int2ipstr (const int ip, char *buf);

struct sockaddr_in;
void PrintClientConnectInfo (const sockaddr_in& clientAddr);
void RecordError(const char* pInfo);

class SocketHolder
{
public:
	SocketHolder();
	~SocketHolder();

	void SetSocketFd(int nSockFd);

private:
	int m_nSockFd;
};
#include "SocketUtil.h"
#include <Windows.h>
#include <iostream>
#include <cassert>

void int2ipstr (const int ip, char *buf) 
{
	sprintf_s(buf, MAX_PATH, "%u.%u.%u.%u", 
		(unsigned char) * ((char *) &ip + 0), 
		(unsigned char) * ((char *) &ip + 1), 
		(unsigned char) * ((char *) &ip + 2), 
		(unsigned char) * ((char *) &ip + 3)); 
}

void PrintClientConnectInfo (const sockaddr_in& clientAddr)
{
	std::cout<<"port = "<<ntohs(clientAddr.sin_port)<<",";
	char ip[MAX_PATH] = {0};
	int2ipstr(clientAddr.sin_addr.s_addr, ip);
	std::cout<<"IP ="<<" "<<ip;
}


void RecordError(const char* pInfo)
{
	int errorCode = WSAGetLastError();
	std::cout<<pInfo<<std::endl;
}

SocketHolder::SocketHolder()
	: m_nSockFd(0)
{
	
}

void SocketHolder::SetSocketFd(int nSockFd)
{
	assert(nSockFd);
	m_nSockFd = nSockFd;
}

SocketHolder::~SocketHolder()
{
	if(m_nSockFd > 0)
		closesocket(m_nSockFd);
	WSACleanup();
}

 

在windows中,客户端程序的流程是 初始化winsock库->创建socket->创建服务器地址(端口和IP)->请求连接->接收响应数据->释放资源

服务器端的流程是  初始化winsock库->创建监听socket->创建监听地址->将监听socket文件描述符与监听地址绑定->开始监听->接收请求->处理请求并响应->继续等待请求

 

客户端输出结果:

服务器端输出结果:

 

服务器端输出结果(客户端运行四次):

客户端输出结果

 

以上的程序可以成功的在客户端输出向服务器请求到的时间,但是我对服务器端getpeername(nConnectedSock,(sockaddr *)&clientAddr,&nSize)得到的客户端机器的地址值不是很理解,我本以为服务器端监听到的socket描述符(88)应该和客户端创建的socket描述符(84) 是相等的,而且端口号也应该是相等的(2013),但每次接到的请求端口号都增加1,该问题有待解决。

补充:

通过向朋友请教并查看资料,对以上提出的两个疑问有了理解。

(1)当服务器端收到一个请求后服务器会产生一个socket句柄,他和客户端创建的是不一样的,这个新产生的句柄是用来连接客户端和服务器的;

(2)服务器收到的请求的客户机的地址中端口一直在变,是因为客户端在通信时是不用绑定端口的,内核会选择一个可用端口进行通信,所以会变。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值