/**//****************************************************
【服务端】基于TCP,多线程的聊天框架代码 评注:非常完整 ******************************************************/ #include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib")
/**//*****************定义客户端连接上后的聊天线程函数************/
DWORD WINAPI ClientThread(LPVOID lpParam) { SOCKET sock = (SOCKET)lpParam;//定义连接客户端的套接字 char szBuff[2048];//定义接收缓冲区 char szMessage[2048];//定义发送的消息 int ret, nLeft, idx;//nLeft,idx用以控制写缓冲的数据,以保证数据写入正确 //提示输入exit退出聊天 puts("输入\"exit\"可退出聊天\n"); //进入数据传输循环,即聊天 //缺陷是只能一人一句来回对话 while(1) { /**////////////////////////// 接收 ///////////////// ret = recv(sock,szBuff,2048,0); if(ret == 0) break; else if(ret == SOCKET_ERROR) { printf("recv() failed:%d\n",WSAGetLastError()); break; } szBuff[ret] = '\0'; //判断对方发过来的是否为exit退出命令,若是则退出聊天继续监听 if(!strcmp(szBuff,"exit")) { printf("对方已经停止聊天!\n"); printf("服务器正在监听"); break; } printf("客户:%s\n",szBuff);//在控制台打印客户的聊天语句 /**/////////////////////////// 回复 ////////////////// printf("发送消息:"); //服务器输入数据回答客户 gets(szMessage); //若发送为空,则传送‘不说话’三字,并提示 if(strlen(szMessage)==0) { printf("发送不能为空哦\n"); strcpy(szMessage,"不说话!"); } //传送数据 nLeft = strlen(szMessage); idx = 0; //确保写进所有数据 while(nLeft>0) { ret = send(sock,&szMessage[idx],nLeft,0); if(ret == 0) break; else if(ret == SOCKET_ERROR) { printf("send error!%d\n",WSAGetLastError()); break; } nLeft-=ret; idx +=ret; } //判断szMessage是否为exit命令,若是则退出聊天继续监听 if(!strcmp(szMessage,"exit")) { printf("连接正在断开!\n"); printf("服务器继续监听\n"); break; } } return 0; }
//主函数 int main(int argc, char* argv[]) { WSADATA wsd;//定义WINSOCK32消息结构体 SOCKET sServSock;//服务器端的套接字 SOCKET sConns;//服务器的各连接 HANDLE hThread;//定义处理客户连接的县城 DWORD dwThreadId;//定义线程ID char szAddress[128];//监听的地址 struct hostent *host = NULL;//定义本地地址指针 sockaddr_in local, client;//分别定义本地,客户端的地址结构 int nSockErr;//定义出错信息 printf("请你输入监听地址(格式如202.204.118.138):"); gets(szAddress); int nAddrLen = sizeof(client);//得到地址结构长度 //初始化Winsock32库 if(WSAStartup(MAKEWORD(2,2),&wsd) != 0) { printf("failed to load winsock!\n"); return 1; } //建立socket对象 sServSock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);//流套接字,面向连接 //为socket分配端口地址监听 local.sin_family = AF_INET; local.sin_port = htons(5150);//监听端口 //若地址出错则监听本机地址 if((local.sin_addr.s_addr = inet_addr(szAddress)) ==INADDR_NONE) { puts("所输入的地址不正确,本服务将使用本机地址!"); //得到主机名 if(gethostname(szAddress,sizeof(szAddress))==SOCKET_ERROR)//得到本机的域名,名称 { puts("Can't getting local host name."); } //通过主机名得到主机IP地址 host = gethostbyname(szAddress);//得到本地ip if(host) CopyMemory(&local.sin_addr,host->h_addr_list[0], host->h_length); else { printf("gethostbyname() failed:%d\n",WSAGetLastError()); Sleep(5000); return 1; } } //将套接字绑定到本机地址local上 if(bind(sServSock,(LPSOCKADDR)&local,sizeof(local))==SOCKET_ERROR) { nSockErr = WSAGetLastError(); printf("bind error:%d!\n", nSockErr); return 1; } //监听客户连接请求 if(listen(sServSock,5)==SOCKET_ERROR) { nSockErr =WSAGetLastError(); printf("listen error:%d\n", nSockErr); return 1; } //提示状态 printf("服务器启动成功!\n"); printf("服务器正在监听\n"); //进入处理连接循环 while(1) { //若有客户连接,则接受连接 sConns = accept(sServSock,(struct sockaddr *)&client,&nAddrLen); if(sConns == INVALID_SOCKET) { nSockErr = WSAGetLastError(); printf("accept error %d\n",nSockErr); break; } //连接正确则提示可以开始聊天 printf("%s:%d连接到了本服务,现在可以聊天了.\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port)); //创建一个线程用于聊天 hThread = CreateThread(NULL,0,ClientThread, (LPVOID)sConns,0,&dwThreadId); if(hThread == NULL) { printf("CreateThread() failed %d\n",GetLastError()); break; } //聊天结束关闭聊天线程,继续监听 CloseHandle(hThread); } closesocket(sServSock); WSACleanup(); return 0; }
/**//*********************************************************** 客户端 ************************************************************/ #include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main(int argc,char **argv) { WSADATA wsd;//定义winsock32信息结构 SOCKET sClient;//定义本地套接字 char szBuffer[2048];//定义接受的缓冲 char szMessage[2048];//发送的消息 char szServer[128];//连接的服务器地址,IP地址 int ret; struct sockaddr_in server;//定义连接的服务器地址 struct hostent *host =NULL;//定义地址 //提示输入连接的服务器地址 printf("请输入连接的服务器IP地址(如:202.204.118.138):"); gets(szServer); //初始winsock库 if(WSAStartup(MAKEWORD(2,2),&wsd)!=0) { printf("Failed to load Winsock library!\n");Sleep(5000); return 1; } // strcpy(szMessage,"我是***"); //建立socket对象 sClient = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sClient == INVALID_SOCKET) { printf("socket() failed :%d\n",WSAGetLastError());Sleep(5000); return 1; } //定义服务器地址以发送信息 server.sin_family = AF_INET; server.sin_port = htons(5150);//端口 server.sin_addr.s_addr = inet_addr(szServer); //若没有地址,则将地址设置为本机地址 if(server.sin_addr.s_addr == INADDR_NONE) { puts("所输入服务器地址不正确,本将使用本机地址!"); //得到主机名 if(gethostname(szServer,sizeof(szServer))==SOCKET_ERROR)//得到本机的域名,名称 { puts("Can't getting local host name."); } //通过主机名得到IP host = gethostbyname(szServer); if(host == NULL) { printf("Unable to resolve server:%s\n",szServer);Sleep(5000); return 1; } CopyMemory(&server.sin_addr,host->h_addr_list[0],host->h_length); } //建立连接 if(connect(sClient,(struct sockaddr *)&server,sizeof(server))==SOCKET_ERROR) { printf("connect() failed:%d\n",WSAGetLastError()); Sleep(5000); return 1; } //提示当前状态 puts("连接成功,现在可以聊天了!\n"); puts("输入\"exit\"可退出聊天\n"); //进入聊天状态 while(1) { /**/////////发送 printf("发送消息:"); //写入发送信息 gets(szMessage); if(strlen(szMessage)==0) { printf("发送不能为空哦\n"); strcpy(szMessage,"不说话!"); } //发送信息 ret = send(sClient,szMessage,strlen(szMessage),0); if(ret == 0) { } else if(ret == SOCKET_ERROR) { printf("send() failed: %d\n",WSAGetLastError()); Sleep(5000); } //判断输入信息是否为exit命令,若是则退出 if(!strcmp(szMessage,"exit")) { printf("你已经退出了聊天!"); break; } // printf("send %d byte\n",ret); /**//////接收回复的信息 ret = recv(sClient,szBuffer,2048,0); if(ret == 0) ; else if(ret == SOCKET_ERROR) { printf("recv()failed:%d\n",WSAGetLastError()); } //设置接收得到的字符串,并打印 szBuffer[ret] = '\0'; if(!strcmp(szBuffer,"exit")) { printf("服务器已经停止聊天!"); break; } printf("服务器:%s\n",szBuffer); } //关闭套接字 closesocket(sClient); //清空winsock环境 WSACleanup(); return 0; }
|