多线程套接字编程-----程序实例(C++实现)

一.程序介绍

该程序主要包括以下内容:

1.多线程程序设计的一般框架,新线程负责循环接收网络数据,一旦收到网络数据就交由主线程处理;主线程负责循环处理网络数据。

2.(UDP)套接字编程的一般框架,为了方便实验该程序只是用到了UDP套接字,没有考虑丢包延迟等网络问题,在实际程序设计中可以采用TCP套接字。

3.如何使用套接字发送多个不同的结构体,通过对不同的结构体添加不同的标志位,从而区分不同的结构体类型。

该程序的默认设置为:

1.各参与者IP地址为127.0.0.1(环回地址,用于单机测试)。
2.编号为i的参与者端口号为10000+i,例如,编号为1的参与者其端口号为10001。由于是采取多机测试,所以每个进程的IP地址都是127.0.0.1,所以需要使用不同的端口,从而区分出不同的进程,这样才能保证网络数据发送到正确的参与者处理。
3.编号为1的参与者向编号为2的参与者发送测试数据。编号为1的参与者向2发送三个不同的结构体,参与者2收到后首先提取结构体的标志位,然后确定用何种结构体变量来接收网络数据。提取到正确的结构体后,打印结构体中的数据。

二.程序源码

1.Node.h

#ifndef NORMALNODE
#define NORMALNODE
#include "winsock.h"
#include "windows.h"
#include 
#include 
using namespace std;

const WM_PARTY_MSG=WM_USER+1;

struct m_struct1
{
	int flag;
	char Value1[15];
};

struct m_struct2
{
	int flag;
	char Value1[15];
	char Value2[15];
};

struct m_struct3
{
	int flag;
	char Value1[15];
	char Value2[15];
	char Value3[15];
};

struct ThreadParameter
{
	int Port;
	DWORD MainThreadID;
};

class Node
{
private:
	int ID;//自身ID
public:
    Node();
	~Node();
	void StartMyThread();
	int DealMessage(char *MyMessage,int MessageLength);
	static DWORD WINAPI StartAcceptThread(LPVOID lpData);
	int SendStruct();
	int TransmitMessage(int ParticipatorID,char *StructBuffer,int BufferLength);
};

#endif

2.Node.cpp

#include "Node.h"
const MSG_STRUCT1=1;
const MSG_STRUCT2=2;
const MSG_STRUCT3=3;

Node::Node()//构造函数
{
	cout<<"***************************************************"<>ID;
}

Node::~Node()//析构函数
{
	
}

void Node::StartMyThread()//启动新线程
{
	DWORD myMainThreadID=::GetCurrentThreadId(); //获取当前线程也就是主线程的ID号
	static ThreadParameter tp;//此处需设置为静态变量
	tp.MainThreadID=myMainThreadID;
	tp.Port=10000+ID;//端口号初始化
    HANDLE hThread = CreateThread(NULL,0,StartAcceptThread,(LPVOID)&tp,0,NULL);//创建新线程
    CloseHandle(hThread);
}

DWORD WINAPI Node::StartAcceptThread(LPVOID lpData)//线程的启动函数,用来循环接收来自参与者发来的轮消息
{
	ThreadParameter tp=*((ThreadParameter *)lpData);
	char RecveBuffer[20][4096];//为了保证,消息能够被安全处理,也就是在消息被线程处理之前,保证没有新的消息覆盖,我们定义了一个二维数组,相当于二十个缓冲区,用来接收数据
	for(int i=0;i<20;i++)
		memset(RecveBuffer[i],0,4096);
    SOCKET RecveSocket = ::socket(AF_INET, SOCK_DGRAM, 0);//创建UDP套接字
	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.S_un.S_addr = INADDR_ANY;	
	sin.sin_port = ::htons(tp.Port);//端口号设置
	if(::bind(RecveSocket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)//地址与套接字绑定
	{
		cout<<"套接字绑定错误!"< 0)
		{
		    //收到网络数据以后向主线程发送消息,并将数据交由主线程处理
			if(PostThreadMessage(tp.MainThreadID,WM_PARTY_MSG,0,(LPARAM)RecveBuffer[recvcount])==0)
			{
				cout<<"向主线程发送消息失败"<


3.testmian,cpp

#include "Node.h"
int main()
{
	int ret;
	WSADATA wsa;
	//初始化套接字DLL
	if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)
	{
		cout<<"套接字初始化失败!"<

三.运行截图

该程序在VC60平台下编译通过


你可能感兴趣的:(C/C++,网络)