首页 > 编程 > C++ > 正文

C++网络编程基础代码(服务器)---基于TCP协议

2019-11-08 03:26:08
字体:
来源:转载
供稿:网友
//网络编程服务器/*服务器端编程的步骤:1:加载套接字库,创建套接字(WSAStartup() / socket());2:绑定套接字到一个ip地址和一个端口上(bind());3:将套接字设置为监听模式等待连接请求(listen());4:请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());5:用返回的套接字和客户端进行通信(send() / recv());6:返回,等待另一连接请求;7:关闭套接字,关闭加载的套接字库(closesocket() / WSACleanup())。*/#include <WinSock2.h>#include <stdio.h>#include <stdlib.h>#PRagma comment(lib, "ws2_32.lib")int main(){	WSADATA wsaData;	int port = 5099;					//自定义的链接端口号,大于1024就行	char buf[] = "I am a Server";	//判断是否可以使用window的网络编程库,初始化sock资源	if (WSAStartup(MAKEWord(2, 2), &wsaData) != 0)	{		printf("Faied to Load winsork");		return 0;	}	//socket函数指定通信协议类型,套接字类型	//int socket(int family, int type, int protocol); // 成功返回非负描述符,出错-1	//family指定协议族,type指定套接字类型,protocol指定某个协议类型常值,或者设为0。	/*family的值有:		AF_INET IPv4协议		AF_INET6 Ipv6协议		AF_LOCAL Unix协议域		AF_ROUTE 路由套接字		AF_KEY 秘钥套接字	type的值有:		SOCK_STREAM 字节流套接字		SOCK_DGRAM 数据报套接字		SOCK_SEQPACKET 有序分组套接字		SOCK_RAW 原始套接字	protocol的值有:		IPPROTO_CP TCP传输协议		IPPROTO_UDP UDP传输协议		IPPROTO_SCTP SCTP传输协议	socket函数在成功时返回一个小的非负整数值,与文件描述符类似,成为套接字描述符,为了得到这个描述符,需要指定协议族和套接字类型,但是并没有指定本地协议地址和远端协议地址。	*/	//创建套接字	SOCKET	sockSrv = socket(AF_INET,SOCK_STREAM,0);	//IPv4 IP协议,字节流传输(TCP传输协议)	//套接字结构体	SOCKADDR_IN	addr;	addr.sin_family = AF_INET;	addr.sin_port = htons(port);						//4个函数来完成主机字节序和网络字节序之间的转换,h表示host,n表示net,s表示short,l表示long														//#include <netinet/in.h>														//uint16_t htons(uint16_t host16bitvalue);														//uint32_t htonl(uint32_t host32bitvalue);														//uint16_t ntohs(uint16_t net16bitvalue);														//uint32_t ntohl(uint32_t net32bitvalue);	addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);		//INADDR_ANY数值为0.0.0.0,表示任何地址都行	/*bind函数把一个本地协议地址赋予一个套接字,它只是把一个协议地址赋予一个套接字,至于协议地址的含义则取决于协议本身。	第二个参数指向协议地址结构的指针,第三个参数是协议地址的长度,对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,或两者都指定,也可以两者都不指定。	bind函数绑定特定的IP地址必须属于其所在主机的网络接口之一,服务器在启动时绑定它们众所周知的端口,如果一个TCP客户端或服务端未曾调用bind绑定一个端口,	当调用connect或listen时,内核就要为响应的套接字选择一个临时端口。让内核选择临时端口对于TCP客户端来说是正常的额,然后对于TCP服务端来说确实罕见的,	因为服务端通过他们众所周知的端口被大家认识的	*/	int retval = bind(sockSrv, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN));	if (retval == SOCKET_ERROR)	{		printf("Failed bind:%d/n", WSAGetLastError());		return 0;	}	/*socket创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的一个客户套接字。	listen函数把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求,调用listen函数将导致套接字从CLOSEE状态转换到LISTEN状态。	第二个参数规定了内核应为相应套接字排队的最大连接个数。*/	if (listen(sockSrv,10) == SOCKET_ERROR)	{		printf("Failed to listen");	}	SOCKADDR_IN	addrClient;	int len = sizeof(SOCKADDR);	while (1)	{ 		//等待客户端请求		//accept函数由TCP服务器调用,用于从已完成队列中列头返回下一个已完成连接,如果已完成队列为空,则进程被投入睡眠(如果该套接字为阻塞方式的话)。		//如果accept成功,那么其返回值是由内核自动生成的一个全新套接字,代表与返回客户的TCP连接,函数的第一个参数为监听套接字,返回值为已连接套接字		SOCKET	sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len);		//连接失败		if (sockConn == SOCKET_ERROR)		{			printf("Accept Failed");			break;		}		//连接成功		printf("Accept client IP:[%s]/n", inet_ntoa(addrClient.sin_addr));			//inet_addr函数是旧函数库的函数,编译时会报错,解决办法,打开项目->属性->配置属性->c/c++ ->SDL检测   将是改为否		//开始收发数据		//发数据		int iSend = send(sockConn, buf, sizeof(buf), 0);		if (iSend == SOCKET_ERROR)		{			printf("Send Failed");			break;		}		//接数据		char recvBuf[100] = {};		recv(sockConn,recvBuf,sizeof(recvBuf),0);		//输出接到的数据		printf("%s/n", recvBuf);		closesocket(sockConn);	}	//关闭开通的套接字接口	closesocket(sockSrv);	//释放资源	WSACleanup();	system("pause");	return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选