服务器端线程负责接收来自多个客户的连接请求,接收来自每个客户端的字符信息,并根据这些字符信息,建立霍夫曼编码,最后将该编码发送给客户端;客户端发送连接请求,建立连接,接受霍夫曼编码并且显示。
server:
#include<winsock2.h>
#include<stdio.h>
#include<string.h>
#pragma comment(lib,"ws2_32.lib")
#include<conio.h>
#include<iostream.h>
#include<stdlib.h>
//using namespace std;
#define MAXVALUE 10000 /*权值最大值*/
#define MAXLEAF 30 /*叶子最多个数*/
#define MAXNODE MAXLEAF*2-1 /* 结点数的个数*/
#define MAXBIT 50 /*编码的最大位数*/
typedef struct node /*结点类型定义*/
{
char letter;
int weight;
int parent;
int lchild;
int rchild;
}HNodeType
typedef struct /*编码类型定义*/
{
char letter;
int bit[MAXBIT];
int start;
}HCodeType;
typedef struct /*输入符号的类型*/
{
char s;
int num;
}lable;
char szHuffman[30]={0};/* 定义二维全局变量数组储存字符 */
char bmHuffman[30][20] = {0}; /* 定义二维全局变量数组用于储存哈夫曼编码字符串 */
int nHuffman = 0; /* 定义一个记录数组中元素个数的全局变量用于回传 */
void HuffmanTree(HNodeType HuffNode[],int n,lable a[])
{
int i,j,m1,m2,x1,x2,temp1;
char temp2;
for (i=0;i<2*n-1;i++) /*结点初始化*/
{
HuffNode[i].letter=0;
HuffNode[i].weight=0;
HuffNode[i].parent=-1;
HuffNode[i].lchild=-1;
HuffNode[i].rchild=-1;
}
for (i=0;i<n-1;i++)
for (j=i+1;j<n-1;j++) /*对输入字符按权值大小进行排序*/
if (a[j].num>a[i].num)
{
temp1=a[i].num;
a[i].num=a[j].num;
a[j].num=temp1;
temp2=a[i].s;
a[i].s=a[j].s;
a[j].s=temp2;
}
for (i=0;i<n;i++)
{
HuffNode[i].weight=a[i].num;
HuffNode[i].letter=a[i].s;
}
for (i=0;i<n-1;i++) /*构造huffman树*/
{
m1=m2=MAXVALUE;
x1=x2=0;
for (j=0;j<n+i;j++)/*寻找权值最小与次小的结点*/
{
if (HuffNode[j].parent==-1&&HuffNode[j].weight<m1)
{
m2=m1;
x2=x1;
m1=HuffNode[j].weight;
x1=j;
}
else if (HuffNode[j].parent==-1&&HuffNode[j].weight<m2)
{
m2=HuffNode[j].weight;
x2=j;
}
}
HuffNode[x1].parent=n+i;
HuffNode[x2].parent=n+i; /*权值最小与次小的结点进行组合*/
HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;
HuffNode[n+i].lchild=x1;
HuffNode[n+i].rchild=x2;
}
}
void HuffmanCode(int n,lable a[])
{
nHuffman = 0; /* 初始化元素个数 */
HNodeType HuffNode[MAXNODE];
HCodeType HuffCode[MAXLEAF],cd;
int i,j,c,p;
HuffmanTree(HuffNode,n,a);
for (i=0;i<n;i++) /*按结点位置进行编码*/
{
cd.start=n-1;
c=i;
p=HuffNode[c].parent;
while (p!=-1)
{
if (HuffNode[p].lchild==c)
cd.bit[cd.start]=0;
else cd.bit[cd.start]=1;
cd.start--;
c=p;
p=HuffNode[c].parent;
}
for (j=cd.start+1;j<n;j++) /*储存编码*/
HuffCode[i].bit[j]=cd.bit[j];
HuffCode[i].start=cd.start;
}
for (i=0;i<n;i++)
{
HuffCode[i].letter=HuffNode[i].letter;
printf(" %c ",HuffCode[i].letter);
szHuffman[nHuffman] = HuffCode[i].letter;
char temp[20] = "";
char c[2] = "";
for (j=HuffCode[i].start+1;j<n;j++)
{
printf("%d",HuffCode[i].bit[j]);
c[0] = HuffCode[i].bit[j]+48; /* 给临时字符串赋值,构成哈夫曼编码 */
strcat(temp, c);
}
strcpy(bmHuffman[nHuffman], temp);/* 哈夫曼编码数组赋值 */
nHuffman++; /* 元素个数+1 */
printf("\n");
}
}
void main()
{
int len=sizeof(SOCKADDR);
char sendBuf[100];//发送至客户端的字符串
char recvBuf[100];//接受客户端返回的字符串
lable data[30];
char *p;
int i,count=0;
WSADATA wsaData;
SOCKET sockServer;
SOCKADDR_IN addrServer;
SOCKET sockClient;
SOCKADDR_IN addrClient;
WSAStartup(MAKEWORD(2,2),&wsaData);
sockServer=socket(AF_INET,SOCK_STREAM,0);
addrServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//INADDR_ANY表示任何IP
addrServer.sin_family=AF_INET;
addrServer.sin_port=htons(6000);//绑定端口6000
bind(sockServer,(SOCKADDR*)&addrServer,sizeof(SOCKADDR));
//Listen监听端
listen(sockServer,5);//5为等待连接数目
printf("服务器已启动:\n监听中...\n");
for (;;)
{
//会阻塞进程,直到有客户端连接上来为止
sockClient=accept(sockServer,(SOCKADDR*)&addrClient,&len);
//接收并打印客户端数据
recv(sockClient,recvBuf,100,0);
printf("接收的字符:%s\n",recvBuf);
for (i=0;i<30;i++)
{
data[i].s=0;
data[i].num=0;
}
p=recvBuf;
while (*p) /*计算字符个数与出现次数(即权值)*/
{
for (i=0;i<=count+1;i++)
{
if (data[i].s==0)
{
data[i].s=*p;
data[i].num++;
count++;
break;
}
else if (data[i].s==*p)
{
data[i].num++;
break;
}
}
p++;
}
printf("\n");
HuffmanCode(count,data);
count=0;
for (i=0; i<nHuffman; i++)
{
// printf("%c %s\n",szHuffman[i],bmHuffman[i]); /* 测试数组中元素是否正常 */
sendBuf[0] = szHuffman[i]; /* 先回传字符 */
sendBuf[1] = '\0';
send(sockClient,sendBuf,100,0);
strcpy(sendBuf, bmHuffman[i]); /* 再回传对应的哈夫曼编码 */
send(sockClient,sendBuf,100,0);
}
send(sockClient, "#\0", 100, 0); /* 以#为标志通知客户端接收完毕 */
//关闭socket
closesocket(sockClient);}
WSACleanup();}
client:
#include<winsock2.h>
#include<stdio.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
char message[100];
printf(" 输入需要编码的字符:");
scanf("%s",message);
WSADATA wsaData;
SOCKET sockClient;//客户端Socket
SOCKADDR_IN addrServer;//服务端地址
WSAStartup(MAKEWORD(2,2),&wsaData);
//新建客户端socket
sockClient=socket(AF_INET,SOCK_STREAM,0);
//定义要连接的服务端地址
addrServer.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//目标IP(127.0.0.1是回送地址)
addrServer.sin_family=AF_INET;
addrServer.sin_port=htons(6000);//连接端口6000
//连接到服务端
connect(sockClient,(SOCKADDR*)&addrServer,sizeof(SOCKADDR));
//发送数据
send(sockClient,message,strlen(message)+1,0);
printf("\n");
char recvmsg[100];
do
{
recv(sockClient, recvmsg, 100, 0);
if (strcmp(recvmsg,"#\0") == 0)
break;
printf("%s ", recvmsg);
recv(sockClient, recvmsg, 100, 0);
printf("%s\n", recvmsg);
}while(1);
//关闭socket
closesocket(sockClient);
WSACleanup();}