/****************************************************
【服务端】基于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;
}
基于TCP,多线程的聊天框架代码
最新推荐文章于 2024-05-22 15:28:52 发布