windows下socket编程,多线程

sercer端

#include <stdio.h>
#include <process.h>
#include <Winsock2.h>
#pragma comment(lib,"ws2_32.lib")
void send(void *a);
void showIP();
SOCKET sockConn;
SOCKADDR_IN addrClient;//连接上的客户端IP地址
void main() 
{
	printf("server's information\n");
	showIP();


	WORD wVersionRequested;   
	WSADATA wsaData;   
	int err;
	wVersionRequested = MAKEWORD(1,1);
	err = WSAStartup(wVersionRequested,&wsaData);
	if ( err != 0 )  
	{
		return; 
	}
	if (LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )  
	{      
		WSACleanup();
		return;   
	}
	//构造监听SOCKET,流式SOCKET
	SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); 


	//配置监听地址和端口:
	SOCKADDR_IN addrSrv;   
	addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);  
	addrSrv.sin_family=AF_INET;  
	addrSrv.sin_port=htons(6003); 


	bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//绑定端口  
	listen(sockSrv,5);
	  
	int len=sizeof(SOCKADDR); 
	sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); //接受客户端连接,获取客户端的IP地址   


	_beginthread(send,0,NULL);
	char recvBuf[50];


	while(1)
	{    
		//char sendBuf[50];
		//char sendMes[50];
		//scanf("%s",sendMes);
		//printf("-->:%s\n",sendMes);
		//sprintf(sendBuf,sendMes,inet_ntoa(addrClient.sin_addr));//组合消息发送出去   
		//send(sockConn,sendBuf,strlen(sendBuf)+1,0);//发送消息到客户端   
		//
		recv(sockConn,recvBuf,50,0);//接受客户端消息   
		printf("<--:%s\n",recvBuf);
	}
	closesocket(sockConn);//断开连接  
} 




void send(void *a)
{
	char sendBuf[50];
	char sendMes[50];
	while (1)
	{
		gets(sendMes);
		printf("-->:%s\n",sendMes);
		sprintf(sendBuf,sendMes,inet_ntoa(addrClient.sin_addr));//组合消息发送出去   
		send(sockConn,sendBuf,strlen(sendBuf)+1,0);//发送消息到客户端  		
	}
	_endthread();
}


void showIP() //定义CheckIP()函数,用于获取本机IP地址 
{
	WSADATA wsaData;
	char name[20];//定义用于存放获得的主机名的变量 
	char *ip;//定义IP地址变量 
	PHOSTENT hostinfo; 


	//调用MAKEWORD()获得Winsock版本的正确值,用于加载Winsock库 
	if ( WSAStartup( MAKEWORD(2,0), &wsaData ) == 0 ) { 
		//现在是加载Winsock库,如果WSAStartup()函数返回值为0,说明加载成功,程序可以继续 
		if( gethostname ( name, sizeof(name)) == 0) { 
			//如果成功地将本地主机名存放入由name参数指定的缓冲区中 
			if((hostinfo = gethostbyname(name)) != NULL) { 
				//这是获取主机名,如果获得主机名成功的话,将返回一个指针,指向hostinfo,hostinfo 
				//为PHOSTENT型的变量,下面即将用到这个结构体 
				ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); 
				//调用inet_ntoa()函数,将hostinfo结构变量中的h_addr_list转化为标准的点分表示的IP 
				//地址(如192.168.0.1) 
				printf("%s\n",ip);//输出IP地址
				printf("%s\n",name);
			} 
		} 
		WSACleanup();//卸载Winsock库,并释放所有资源 
	}
} 


 
client端 

#include <stdio.h> 
#include <Winsock2.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")  
SOCKET sockClient;
void send(void *p);
void main()
{      
	WORD wVersionRequested;      
	WSADATA wsaData;//WSAata用来存储系统传回的关于WinSocket的信息     
	int err;      
	wVersionRequested = MAKEWORD(1,1);      
	err = WSAStartup( wVersionRequested, &wsaData);  
	if ( err != 0 )  
	{
		return;     
	}
	if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 )      
	{          
		WSACleanup();
		return;     
	}      
	sockClient=socket(AF_INET,SOCK_STREAM,0);//AF_INET表示TCP连接     //初始化连接与端口号     
	SOCKADDR_IN addrSrv;  
	char IP[20];
	printf("Please input server's IP:  ");
	scanf("%s",IP);
	addrSrv.sin_addr.S_un.S_addr=inet_addr(IP);//本机地址,服务器在本机开启     
	addrSrv.sin_family=AF_INET;      
	addrSrv.sin_port=htons(6003);//设置端口号
	connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//连接服务器
	int hand = _beginthread(send,0,NULL);
	char recvBuf[50];
	while (1)
	{
		
		//char sendMes[50];
		//scanf("%s",sendMes);
		recv(sockClient,recvBuf,50,0);//接受数据
		printf("<--:%s\n",recvBuf);
		//printf("-->:%s\n",sendMes);
		//send(sockClient,sendMes,strlen(sendMes)+1,0);//发送数据 
		
	}
	closesocket(sockClient);//关闭连接      
	WSACleanup();
	system("pause");
}


void send(void *p)
{
	char sendMes[50];
	while (1)
	{
		gets(sendMes);
		printf("-->:%s\n",sendMes);
		send(sockClient,sendMes,strlen(sendMes)+1,0);//发送数据 
	}
	_endthread();
}


相关推荐
网关程序:主要目的是作了一个中间程序转发网络消息,其实在网上有很多这样的程序,<br>比如跨平台的ACE,目前版本为5.6,如果从ACE开始学习网关,个人觉得挺费劲的,<br>我也曾经想用ACE编写网关程序,后来由于ACE的复杂性,还是胆怯了,还是自己下定决<br>心写了一个网关程序。<br>该网关程序目前只支持Windows,下一步的目标准备将程序移植到GCC环境下。<br>程序中用到STL的std::map和std::list,也大量的运行了模板类,如:关于线程的参数<br>ARGS即为模板类:template <class T> ARGS{}、还有一个就是SOCKET结构体:<br>HOSTSTRUCTSTRCT的定义也是用到了模板类。<br><br>程序的主要部份为:class CFramework 文件:framework.h framework.cpp,<br>如果想编写一个网关程序,首先需要从该类继承,如目前例程中的:class CMyGateway;<br><br>大家都知道网关程序即SOCKET通讯多线程程序,其中当然用到SOCKET;网关中有SOCKET服务端,<br>也有SOCKET客户端;作为SOCKET服务端时,需要接收远程主机的连接,当远程主机请求连接,<br>根据业务需要首先要验证该客户端是否是合法的客户,此时,需要从系统的允许访问队列表<br>查询是否有该主机的信息,如果有该主机的信息,则允许该主机连接,此时触发OnConnected事件,<br>在该事件中,可以接收客户端的登录信息,验证客户端的登录信息,如果验证成功,<br>则将该主机信息添加到系统路由表中,当有消息需要转发到该主机时,从系统路由表取到目标<br>主机的信息,通过host.fd发送消息;同理,网关作为一个客户端时,需要连接其它远程服务器,<br>一旦连接上后,触发OnConnected事件,在该事件中,我们可以发送登录信息,并接收应答信息,<br>解析应答信息,判断我们的登录是否成功,如果成功的话,将连接主机的信息添加到系统路由表<br>中,当有其它信息需要转发到该主机时,从系统路由表中取到连接信息通过send() host.fd转发信息。<br><br>在class CFramework中还有一定非常重要的函数:OnExecuteMessagte(const xuwn::MESSAGE& message)方法,<br>这个方法是在从消息队列取到消息后执行的,xuwn::MESSAGE中定义了一个buffer即收到的消息,<br>同时消息的长度为:message.size.nhead+message.size.nbody,您可以处理消息,在模拟程序中,<br>我将消息转发到另外一个服务器即:B_HOST,HOSTSTRUCT的有个字段name即我称之为节点名称,<br>该名称是我作为索引用的,在系统路由中只能存在这样一个KEY值的HOSTSTRUCT;<br><br>在class CFramework中还有一个重要函数:OnRecvData(const HOSTSTRCT& host__, xuwn::MESSAGE& message),<br>这个方法是由我们执行如何接收消息的,因为大多数时候我们定义消息都为变长,即消息存在消息头+消息体,<br>大多时候,消息头为定长,消息体的长度在消息头中体现,当我们接收完消息头后,设置后继包(消息体)的长度,<br>再调用CFramework::OnRecvData(host__, message)去接收消息体,并把消息写入到消息队列中。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页