栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

使用C++调用Socket接口实现简易TCP服务器

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用C++调用Socket接口实现简易TCP服务器

本人是一名电子信息工程专业的大xio生;在用stm32玩了几个项目以后感觉;哦,这个世界尽在我手,统治世界指日可待,可是在远程操控单片机器件的时候碰到了问题——网络调试蓝牙调试助手使用起来太鸡肋惹;为了实现控制单片机的方便以便于早日统治世界;我学废了使用TCP协议(准确来说就会一个socket接口)来更加“方便”地控制单片机;

TCP协议是什么

度娘爱老虎油

socket又是什么

首先这玩意翻译过来叫做套接字;简单来说这个精致玩意是一组接口;它把复杂的TCP/IP协议都藏起来了,方便我们可以更好地去利用这个实现TCP/IP协议。
那么它是怎么实现的嘞?用一个比较通俗的小李子来解释;比如说嘞,我是一个社交牛杂人士;我要到了一个灰常好看的小姐姐的电话,我今天就决定给她打电话(小姐姐襤襤襤)
首先从通俗情况下来讲我们要正常完成给小姐姐打电话的过程,小姐姐的手机那必须得在信号范围内对不对,我们在使用socket操作的第一步就是打开网络库;

其次小姐姐的手机里面要装的电话卡就是我要打的电话号码对应的那一张,这里我们把电话号码想象成为IP地址和端口,这里就对应socket里面的socket绑定IP和端口的操作;

手机能够随时接电话,那么手机的cpu一定开启了对电话卡进行监听的操作,这里就对应socket的监听操作了;

当我鼓起勇气打过去,小姐姐接到了电话,此时就对应socket的接受连接操作了,在我没有打电话过去的时候,小姐姐的手机是需要处于等待接收电话的状态,这样我们打过去电话,小姐姐的手机才能立马有反应(小姐姐接不接就是另外一回事了);

接下来实现小姐姐和我对话,小姐姐很高冷,只有我在和她说过话以后她才会吱一声,这里我们把我给小姐姐说的话当作请求,她回过来的话作为回应;这就实现了TCP的主机和客户端的交互过程;
最后我反应过来了,小丑原来是我自己嵐嵐嵐,我挂断了电话,小姐姐那边也挂断了电话,对应的就是socket的关闭操作。

总体运行情况是jie个样子的

代码实现

正题来惹;我们咋个用代码来实现的嘞;
首先,我们需要打开网络库,这样我们对应的函数才能开始使用哦,WSAStartup就是为了向操作系统说明,我们要用哪个库文件,让该库文件与当前的应用程序绑定,从而就可以调用该版本的socket的各种函数了。

int WSAStartup(_In_ WORD wVersionRequested, _Out_ LPWSADATA lpWSAData);

wVersionRequired:
这是一个我们需要的网络库版本号,我们直接用 MAKEWORd(2, 2) 的返回值就好啦;
lpWSAData:
这是一个WSADATA的指针;WSADATA是一个结构体, WSAStartup()函数会将环境的网络库信息存在这个结构体中。
它的返回值为0时,那么就打开成功了
为其他返回值时

一般对应出现的问题:

SOCKET socket(int domain, int type, int protocol);

这个函数建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1;通俗来讲第一个对应的是选择的协议,第二个选择套接字的类型,第三个是选择的协议的类型;这个函数会传出一个soket描述符,通过这个函数就可以创建套接字啦,哟西~

bind(SOCKET s,reads_bytes_(namelen) const struct sockaddr FAR * name,int namelen);

这个函数是绑定IP和端口号的操作

int listen(SOCKET sockfd, int backlog);

这个函数实现监听的操作,在网络通信中, 客户端通常处于主动的一方, 而服务器则是被动的一方;服务器是被连接的, 所以他要时刻准备着被连接, 所以就需要调用 listen() 来监听,;等着被连接.爛爛爛

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept() 函数的作用就是在已完成连接队列中取出一个已经建立好的连接;通过这个就能实现选择连接对象;在没有链接的时候这个函数会处于阻塞状态;

recv(SOCKET s,writes_bytes_to_(len, return) data_source(NETWORK)char FAR * buf,int len,int flags);

这个就是从连接对象哪里读取数据过来的操作啦!!!第一个传入变量是accept返回的新的socket描述符,第二个就是我们存储数据的一个字符串数组,第三个变量为数组长度,第四个,就是个0,甭管。

int send(int s, const void * msg, int len, unsigned int falgs);

这个和前者大致相同,最后一位0;
最后就是关闭socket接口啦

int PASCAL FAR closesocket ( IN SOCKET s);

参数就是对应的你要关闭的socket啦

int PASCAL FAR WSACleanup(void);

关闭网络库。
主要的函数就讲完啦,下面的代码可以实现接受客户端信息并显示:

#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#include   
#include  //window下的网络编程头文件

#pragma comment(lib,"ws2_32.lib")  //将ws2_32.lib加入工程文件中
WSADATA initdata;

int WSAInit(void);


int main(void) {
	if (WSAInit() != 0)return 0;//打开网络库
	SOCKET socketlisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建socket
	if (socketlisten == INVALID_SOCKET) {
		printf("socket创建失败");
		return 0;
	}

	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8080);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	if (bind(socketlisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)//绑定IP
	{
		printf("IP与端口绑定失败!n");
	}

	if (listen(socketlisten, 5) == SOCKET_ERROR)
	{
		printf("监听失败!n");
		return 0;
	}

	SOCKET sClient;
	sockaddr_in remoteAddr;
	int nAddrlen = sizeof(remoteAddr);
	char revData[255];

	while (1) {//建立连接
		printf("等待连接...n");
		sClient = accept(socketlisten, (SOCKADDR*)&remoteAddr, &nAddrlen);//返回一个新的socket描述符,在这里,如果没有连接则会阻塞直到有链接
		if (sClient == INVALID_SOCKET)
		{
			printf("接收应答失败!");
			continue;
		}
		printf("接受到来自%s的连接rn", inet_ntoa(remoteAddr.sin_addr));//inet_返回客户端ip
		break;
	}

	while (1)//循环接收数据  
	{
		int ret = recv(sClient, revData, 255, 0);//读取到发来的数据
		if (ret > 0)
		{
			revData[ret] = 0x00;
			printf(revData);
			printf("n");
		}

		//每得到一次数据就发送一次数据表示接收成功  
		const char* sendData = "hello usern";
		send(sClient, sendData, strlen(sendData), 0);
		
		//这里是关闭socket并终止Ws2_32.dll的使用
		
	}

}
int WSAInit() {
	int WSAstate= WSAStartup(MAKEWORd(2, 2), &initdata);
	switch (WSAStartup(MAKEWORd(2, 2), &initdata)) {
	case 0:printf("网络库打开成功n"); break;
	case WSASYSNOTREADY:printf("请检查网络库n"); break;
	case WSAVERNOTSUPPORTED:printf("请更新网络库n"); break;
	case WSAEINPROGRESS:printf("请重新启动n"); break;
	case WSAEPROCLIM:printf("有一些软件正在占用所需网络资源n"); break;
	}
	return WSAstate;
}

第一行是为了防止
这憨憨玩意儿报错,看别个大佬说这是因为inet_addr是一个老函数,而微软就是喜欢强迫别人用它的新函数。这里我就直接让它强制正确啦;还有别的方法大家可以去挖掘挖掘。
最后我用手机上面的网络助手去连接电脑

电脑端
因为两端用的是UTF8格式,所以就传不了中文啦,嘿嘿。
按道理能够做出这样子的话,用stm32接esp8266连接电脑服务端就没得问题,我离统治世界又近了一步

这是我第二次写博客,写的不好多多见谅。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/849339.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号