网络编程学习笔记一 第一个服务器端程序

在坎坷路途中的第一个服务器端程序

 

能注释的地方我都注释了,因为才学2天,大家如果看到有什么地方有问题的请帮忙指出来。

 

 

// T2Server.cpp : 定义控制台应用程序的入口点。
//



#include<iostream>

#include<WinSock2.h>

#pragma comment(lib,"WS2_32")

using namespace std;

#define REQUEST_BACKLOG 5


//如果想要使用SOCKET,WSAStartup函数必须要进行初始化才可以
bool initWSA(const WORD &wVersion ,WSADATA *wsadata)
{
	int Ret = 0;
	if(Ret = WSAStartup(wVersion,wsadata)!=0)
	{
		cout<<"WSAStartup Error "<<Ret<<endl;

		return FALSE;
	}
	return true;
}


void cleanWSA()
{
	if(WSACleanup() == SOCKET_ERROR)
	{
		cout<<"WSACleanup failed ,error"<<WSAGetLastError()<<endl;
		
	}
}

//这个是初始化服务器地址,包括IP地址和端口
void InitSockAddrByIP(SOCKADDR_IN *pSockAddr ,const char FAR*strIP,const INT &nPortID)
{
	pSockAddr->sin_family = AF_INET;

	//htons这个不能忘了,网络字节序必须要转换,不然经常会出大问题
	pSockAddr->sin_port = htons(nPortID);

	if(0!=strlen(strIP))
	{

		pSockAddr->sin_addr.S_un.S_addr = inet_addr(strIP);
	   // pSockAddr->sin_addr.S_un.S_addr = htonl(INADDR_ANY);
		cout<<inet_ntoa(pSockAddr->sin_addr)<<endl;
     	//pSockAddr->sin_addr.s_addr = inet_addr(strIP);
		 // pSockAddr->sin_addr.s_addr =htonl(inet_addr(strIP));
	}
	else
	{
		
		pSockAddr->sin_addr.S_un.S_addr =htonl(INADDR_ANY);
	}
}

//将端口地址对象和sock对象进行绑定,也就是和后文的sock_listen对象
bool bindAddr(const SOCKADDR_IN * pSockAddr ,SOCKET pSocket)
{
	int bindResult = bind(pSocket,(sockaddr*)(pSockAddr),sizeof(SOCKADDR_IN));

	if(SOCKET_ERROR == bindResult)
	{
		cout<<"bind error : "<<WSAGetLastError()<<endl;
		return false;
	}
	else
		return true;
}

//这个是创建监听器,一旦有连接请求和发送信息的请求我们就能接收到了
bool SetListen(SOCKET s,int backlog)
{
	int ListenResult = listen(s,backlog);

	if(SOCKET_ERROR == ListenResult)
	{
		cout<<"listen error"<<WSAGetLastError()<<endl;
		return false;
	}
	else
	return true;
}


int main()
{
	WSADATA wsadata;
	if(!initWSA(MAKEWORD(2,2),&wsadata))
	{
		return 0;
	}

	
	//指定连接IP地址和服务器端口
    SOCKADDR_IN internetAddr;
	memset(&internetAddr, 0, sizeof(struct sockaddr_in));
	char FAR *strIP ="192.168.1.101";//这个是服务器的IP地址
	INT nPortID = 5150;
	InitSockAddrByIP(&internetAddr,strIP,nPortID);
	

	//创建listener_socket
	SOCKET listener_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(INVALID_SOCKET ==listener_socket)
	{
		cout<<"listener_socket creat failed"<<endl;
		return 0;
	}


	if(!bindAddr(&internetAddr,listener_socket))
		return 0;
		
   
	
	if (!SetListen(listener_socket, REQUEST_BACKLOG ) ) 

    { 
        return 0; 

    } 

	cout<<"server started ~~~"<<endl;


	//创建socket保存结构
	fd_set fdSocket;
	FD_ZERO(&fdSocket);
	FD_SET(listener_socket,&fdSocket);


	//查找可读的socket
	while(1)
	{



		//这个只是一个缓冲对象
		fd_set fdSocket_temp;
        FD_ZERO(&fdSocket_temp);
		fdSocket_temp = fdSocket;

		//这个是读用的
		fd_set fdRead;
		FD_ZERO(&fdRead);
		fdRead = fdSocket;

		//这个是catch错误用的
		fd_set fdExceptds;
		FD_ZERO(&fdExceptds);
		fdExceptds = fdSocket;

		//除了第一个参数,第二个参数是读fd_set对象,第三个参数是写fd_set对象,第四个参数是catch错误的fd_set对象
		int nResult_select = select(0,&fdRead,NULL,&fdExceptds,NULL);

		//这个时候表示有消息了
		if(0 <nResult_select)
		{
			int socket_count =  fdSocket_temp.fd_count;

			for(int i =0;i<socket_count;i++)
			{
				//如果现在fdRead里有消息传来
				if(FD_ISSET(fdSocket_temp.fd_array[i],&fdRead))
				{
					if(fdSocket_temp.fd_array[i]==listener_socket)
						//如果是当前正在监听的表示这个还未接受连接,那我们就接下来连接就好了,其他的已经连接上的就接收信息就好了
					{
						if(fdSocket.fd_count<FD_SETSIZE)
						{
							//接受这个新的连接
							SOCKADDR_IN ClientAddr;
							int addrlen = static_cast<int>(sizeof(ClientAddr));   //一定要赋值 

							SOCKET newClient_SOCKET = accept(listener_socket,(sockaddr *)&ClientAddr,&addrlen);
						    cout<<inet_ntoa(ClientAddr.sin_addr)<<endl;
							if(INVALID_SOCKET==newClient_SOCKET)
							{
								cout<<"accep error "<<WSAGetLastError()<<endl;
							}
							else
							{
								FD_SET(newClient_SOCKET,&fdSocket);
								cout<<"add new connect"<<endl;
							}

						}
						else
						{
							cout<<"too much connecttion"<<endl;
						}
					}
					//已经连接上了的我们就直接接收数据好了
					else
					{
						char recvbuff[1024];
						int  ret = 0;

						ret = recv(fdSocket_temp.fd_array[i],recvbuff,static_cast<int>(strlen(recvbuff)),0);

						if(ret>0)
						{
							recvbuff[ret]='\0';
							cout<<"recv: "<<recvbuff<<endl;

							//回复给客户端
							char backbuf[1024]="recevie OK";
							send( fdSocket_temp.fd_array[i], backbuf, static_cast<int>( strlen(backbuf) ), 0 ); 

					
						}

						else  //此时ret返回值为0
						{
							//连接已经断开了。断开有很短原因
							closesocket(fdSocket_temp.fd_array[i]);
							//在fd_set中去掉这个连接
							FD_CLR(fdSocket_temp.fd_array[i],&fdSocket );
						}

					}

				}

				//既然没有发送消息又占用了连接的位置,我们就释放他来控制空闲的空间
				else if(fdSocket_temp.fd_array[i] != listener_socket )
				{
					  //该连接断开 

                    closesocket( fdSocket_temp.fd_array[i] ); 

                    FD_CLR( fdSocket_temp.fd_array[i], &fdSocket ); 


				}

				//如果Catch到了错误
				if(FD_ISSET(fdSocket_temp.fd_array[i],&fdExceptds)&&  (fdSocket_temp.fd_array[i] != listener_socket) ) 

				{
					 //该连接断开 

                    closesocket( fdSocket_temp.fd_array[i] ); 

                    FD_CLR( fdSocket_temp.fd_array[i], &fdSocket ); 


				}
			}
		}

		  else if( SOCKET_ERROR ==nResult_select ) 

        { 

            cout << "select error : " << WSAGetLastError() << endl; 

            return 0; 

        } 

		Sleep(50);//这个必须要,不然死循环一直弄下去机子可能会死去。。

	}

	closesocket(listener_socket);
	cleanWSA();
	
	return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值