[Windows网络编程课设]南工程聊天室客户端源码

南工程聊天室客户端源码
南京工程学院通信工程学院的《Windows网络编程》一课的课程设计源码,聊天室的搭构需要服务器和客户端。服务器源码请看上一篇博文,都有贴出。备注也很详细,可以参考一下。不过作为聊天室功能也很多的,我这里贴出的代码功能实现的并不全面。如果有同学对此作出改进,希望可以交流一下。
MyMsg.h
#pragma once
/************************************************************
*  文件名:MyMsg.h
*  描述:  服务器和客户端共用的头文件,消息定义
*************************************************************/
#ifndef _MYMSG_H_
#define _MYMSG_H_

enum {
	LOGIN_MSG,           //登录
	LOGIN_MSG_RES,       //登录响应
	QUERY_FQQ,           //查询单个好友QQ
	QUERY_FQQ_RES,       //查询单个好友QQ的响应
	TALK_MSG,             //聊天
	REQUEST_ALL_FRD,      //请求所有qq好友信息
	APPLY_ALL_FRD        //应答所有qq好友信息
};

struct LoginMsg {
	unsigned char id;  //消息编号
	char qq[6];        //登录ID号
};

struct LoginMsgResponse {
	unsigned char id;  //消息编号
	unsigned char isOK;
	char reason[100];    //如果失败,则在此写入失败原因
};

struct FriendQqMsg {
	unsigned char id;  //消息编号
	char qq[6];
};

struct FriendQqMsgResponse {
	unsigned char id;  //消息编号
	unsigned char isOK;
};

struct TalkMsg {
	unsigned char id;  //消息编号
	char qq[6];
	char fqq[6];
	char info[200];
};

struct RequestAllFriend {
	unsigned char id;   //消息编号
};

struct AllFriendMsg {
	unsigned char id;  //消息编号
	char qq[6];
};

#endif

MyTcp.cpp
/************************************************************
*  文件名:MyTCP.cpp
*  描述:  TCP/IP通信socket封装
*************************************************************/
#include <stdio.h>
#include <WinSock2.h>
#include "MyTools.h"
#pragma comment (lib, "ws2_32.lib")

#define PORT 5001
int ls;   //侦听套接字
int flag;//记录服务器或是客户端的标志

		 /*   描述: 初始化服务器或客户端, 该函数在使用中必需首先调用,客户端和服务器 */
int initSock(int IsServer)
{
	WSADATA data;

	if (WSAStartup(1, &data) <0)
		printMsgExit("call WSAStartup() failure!");

	ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ls < 0)
		printMsgExit("创建套接字失败!");

	flag = IsServer;
	if (IsServer != 0)
	{//服务器
		struct sockaddr_in servAddr;
		memset(&servAddr, 0, sizeof(servAddr));
		servAddr.sin_family = AF_INET;
		servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
		servAddr.sin_port = htons(PORT);

		if (bind(ls, (struct sockaddr *)&servAddr, sizeof(servAddr))<0) {
			printMsg("bind套接字失败!\n");
			return -1;
		}

		if (listen(ls, 10)<0) {
			printMsg("listen套接字失败!\n");
			return -1;
		}
	}

	return 0;
}

/*   描述: 仅用于客户端, 连接服务器 */
int tcpConnect(const char *serverIP, unsigned short port)
{
	struct sockaddr_in servAddr;

	memset(&servAddr, 0, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_addr.s_addr = inet_addr(serverIP);
	servAddr.sin_port = htons(port);

	if (connect(ls, (struct sockaddr *)&servAddr, sizeof(servAddr))<0)
	{
		printMsgExit("连接服务器失败!\n");
	}

	return ls;
}

/* 描述: 发送数据 */
int tcpSend(unsigned int sock, const char *sendBuf, int sendBufLen)
{
	int len = send(sock, sendBuf, sendBufLen, 0);
	return len;
}

/* 描述: 接收数据 */
int tcpRecv(unsigned int sock, char *recvBuf, int recvBufLen)
{
	int len = recv(sock, recvBuf, recvBufLen, 0);
	return len;
}

void tcpClose(unsigned int sock)
{
	closesocket(sock);
	WSACleanup();
}

MyTcp.h
#pragma once
/************************************************************
*  文件名:MyTCP.h
*  描述:  TCP通信头文件
*************************************************************/
#ifndef _MYTCP_H_
#define _MYTCP_H_

int initSock(int IsServer);
int tcpConnect(const char *serverIP, unsigned short port);
int tcpAccept();
int tcpSend(unsigned int sock, const char *sendBuf, int sendBufLen);
int tcpRecv(unsigned int sock, char *recvBuf, int recvBufLen);
void tcpClose(unsigned int sock);

#endif 

MyTools.cpp
/************************************************************
*  文件名:MyTools.cpp
*  描述:  共用的文件,工具函数定义
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "MyTools.h"

extern int flag;

void printMsg(const char * msg) {
	if (flag)
		printf("\t【南工服务器豪华版】%s", msg);
	else
		printf("\t【南工客户端豪华版】%s", msg);
}

void printInt(int value) {
	if (flag)
		printf("\t【南工服务器豪华版】%d", value);
	else
		printf("\t【南工客户端豪华版】%d", value);
}

void printMsgExit(const char * msg) {
	printMsg(msg);
	exit(0);
}

void printIntExit(int value) {
	printInt(value);
	exit(0);
}
MyTools.h
#pragma once
/************************************************************
*  文件名:MyTools.h
*  描述:工具函数定义
*************************************************************/
#ifndef _MYTOOLS_H_
#define _MYTOOLS_H_
void printMsgExit(const char * msg);
void printMsg(const char * msg);
void printInt(int value);
void printIntExit(int value);
#endif

TalkClient.cpp
/************************************************************
*  文件名:TalkClient.cpp
*  描述:  客户端入口,界面操作
*************************************************************/
#include <stdio.h>
#include <Windows.h>

#include "TalkClientService.h"

void displayMenu();
void exitProc();
void defProc();
void procMenu();

char serverip[6];

int main(int argc, char *argv[])
{   
	if (argc < 2)
	{
		printf("请输入服务器的IP地址。。。\n");
		return 0;
	}
	strcpy(serverip, argv[1]);
	displayMenu();
	procMenu();
	while (1) Sleep(10000);
}

char ch;     //菜单选择
void displayMenu()
{
	static int t = 1;
	if (t++ == 1)
	{
		printf("\n\n\n\n\n");
		printf("\n\t      @                                                             @        ");
		printf("\n\t    @ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @      ");
		printf("\n\t   @  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   @    ");
		printf("\n\t  @   **      **  **********  **        **         ********   **  **     @   ");
		printf("\n\t @    **      **  **          **        **        **      **  **  **      @  ");
		printf("\n\t @    **      **  **          **        **        **      **  **  **       @  ");
		printf("\n\t @    **********  **********  **        **        **      **  **  **       @  ");
		printf("\n\t @    **      **  **          **        **        **      **  **  **       @  ");
		printf("\n\t @    **      **  **          **        **        **      **              @  ");
		printf("\n\t  @   **      **  **********  ********  ********   ********   @@  @@     @   ");
		printf("\n\t   @   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  @    ");
		printf("\n\t    @  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^@      ");
		printf("\n\t      @                                                             @        ");

		printf("\n                                                             -----By Hins    ");
		printf("\n\n\n\n\n\t\tPress 'Enter' to enter the menu......");           /*按任一键进入主菜单*/
	}
	getchar();                                 /*从键盘读取一个字符,但不显示于屏幕*/
	system("cls"); /*清屏*/
	printf("\n");
	printf("\n");
	printf("\n");
	printf("\t************************************************\n");
	printf("\t*                                              *\n");
	printf("\t*         南工2016聊天客户端程序               *\n");
	printf("\t*         Version 2.1     豪华版               *\n");
	printf("\t*                                              *\n");
	printf("\t*                                              *\n");
	printf("\t*                                              *\n");
	printf("\t*           1) 登录(L)                         *\n");
	printf("\t*           2) 退出(e)                         *\n");
	printf("\t*                      by---HinsShwan          *\n");
	printf("\t************************************************\n");
	printf("\n");
	connectServer();
	printf("\t您的选择是:");
	ch = getchar();
}

void procMenu()
{
	switch (ch)
	{
	case 'l':
	case 'L':
	case '1':
		statusConnected();
		break;

	case 'e':
	case 'E':
	case '2':
		exitProc();
		break;

	default:
		defProc();
	}
}

void exitProc()
{
	printf("\t客户端程序已经终止!\n");
	exit(0);
}

void defProc()
{
	printf("\t 输入字符错误!\n");
}

TalkClientService.cpp
/************************************************************
*  文件名:TalkClientService.cpp
*  描述:  客户端业务实现
*************************************************************/
#include "MyTCP.h"
#include "MyTools.h"
#include "TalkClientService.h"
void myRecvThread();
#define PORT 5001


extern char serverip[6];

char qq[6] = { 0 };
char fqq[6] = { 0 };
int sock;

int status = STUS_START;

void mainProc()
{
	while (1)
	{

		switch (status)
		{
		case STUS_CONNECTED:
			statusConnected();
			break;

		case STUS_WAIT_LOGIN_RES:
			printMsg("等待服务器响应..........\n");
			Sleep(1000);
			break;

		case STUS_LOGINED:
			statusLogined();
			break;

		case STUS_WAIT_QUERY_FQQ_RES:
			printMsg("等待服务器响应..........\n");
			Sleep(1000);
			break;

		case STUS_TALK:
			statusTalk();
			break;
		case STUS_WAIT_QUERY_ALLQQ_RES:
			printMsg("等待服务器响应..........\n");
			Sleep(1000);
			break;
		}
	}
}

void statusTalk()
{
	printMsg("退出聊天(Exit) 我说>>");
	setbuf(stdin, NULL);   //清空键盘缓冲区

	char buf[1024] = { 0 };
	gets_s(buf);
	if (strcmp(buf, "Exit") == 0)
	{
		printMsg("客户端已经退出!\n");
		statusLogined();
	}

	else
	{
		struct TalkMsg msg;

		msg.id = TALK_MSG;
		strcpy(msg.qq, qq);
		strcpy(msg.fqq, fqq);
		strcpy(msg.info, buf);
		status = 5;
		tcpSend(sock, (const char *)&msg, sizeof(msg));
	}

	return;
}

void statusLogined()
{
	char buf0[10] = { 0 };
	int rt = 0;
	while (rt == 0)
	{
		memset(buf0, 0, sizeof(buf0));
		printMsg("显示在线好友(L)|找好友聊天(T)|退出(E) 默认(T)>>");
		setbuf(stdin, NULL);   //清空键盘缓冲区
		gets_s(buf0);
		if (strcmp(buf0, "T") == 0 || strcmp(buf0, "t") == 0)
		{
			printMsg("选择聊天好友......\n");
			while (1)
			{
				printMsg("输入聊天好友QQ号(最多不超过5位):  退出请输入“quit”");
				char tmp[1024];
				scanf("%s", tmp);
				if (strlen(tmp) > 5)
				{
					printMsg("您输入的qq号长度大于5个,请重新输入\n");
				}
				else if (strcmp(tmp, qq) == 0)
				{
					printMsg("您输入的qq号是自己号码,难道您要自言自语吗?::) 请重新输入\n");
				}
				else if (strcmp(tmp, "quit") == 0)
					break;
				else
				{   //发送要聊天的好友QQ号给服务器
					struct FriendQqMsg msg;
					msg.id = QUERY_FQQ;
					strcpy(msg.qq, tmp);
					strcpy(fqq, tmp);
					status = STUS_WAIT_QUERY_FQQ_RES;
					tcpSend(sock, (const char *)&msg, sizeof(msg));
					rt = 1;
					break;
				}
			}
		}
		else if (strcmp(buf0, "L") == 0 || strcmp(buf0, "l") == 0)
		{
			char buf2[10] = { 0 };
			memset(buf2, 0, sizeof(buf2));
			struct RequestAllFriend res;
			res.id = REQUEST_ALL_FRD;
			memcpy(buf2, &res, sizeof(res));
			tcpSend(sock, (const char*)buf2, sizeof(buf2));
			status = STUS_WAIT_QUERY_ALLQQ_RES;
			Sleep(100);
		}
		else if (strcmp(buf0, "E") == 0 || strcmp(buf0, "e") == 0)
		{
			printMsg("客户端已经退出!\n");
			exit(0);
		}
		else
		{
			printMsg("输入内容错误(手抖了吧-_-),请重新输入\n");

		}


	};

}

void connectServer()
{
	printMsg("开始连接服务器......\n");
	initSock(0);  //客户端
	sock = tcpConnect(serverip, PORT);
	printMsg("连接服务器成功!\n");

	//创建一个线程用于接收服务器发送的信息
	DWORD threadId;
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)myRecvThread, NULL, 0, &threadId);
}

//创建接收线程专用于接收并处理服务器返回的收数据
void myRecvThread()
{
	char buf[1024] = { 0 };
	while (1)
	{
		memset(buf, 0, sizeof(buf));
		tcpRecv(sock, buf, sizeof(buf));
		unsigned char id = (unsigned char)buf[0];
		switch (id)
		{
		case LOGIN_MSG_RES:
			procLoginMsgResponse((struct LoginMsgResponse *)buf);
			break;

		case QUERY_FQQ_RES:
			procFriendQqMsgResponse((struct FriendQqMsgResponse *)buf);
			break;

		case TALK_MSG:
			procTalkMsg((struct TalkMsg *)buf);
			break;
		case APPLY_ALL_FRD:
			procApplyAllFriend((struct AllFriendMsg *)buf);
			break;

		}
	}
	sprintf(buf, "结束myRecvThread线程:%d.........\n");
	printMsg(buf);
	exit(0);
}

void statusConnected()
{
	printMsg("\n\t请输入登录信息\n");

	while (1)
	{
		printMsg("本机的QQ号(最多不超过5位数字):");
		char tmp[1024];
		scanf("%s", tmp);
		int  i;
		if (strlen(tmp)>5)
		{
			printMsg("您输入的qq号长度大于5个,请重新输入\n");
			continue;
		}

		for (i = 0;i<strlen(tmp);i++)
		{
			if (tmp[i] >= '0' && tmp[i] <= '9')
			{
				continue;
			}
			else
				break;
		}

		if (i == strlen(tmp))
		{
			strcpy(qq, tmp);
			break;

		}
		else
		{
			printMsg("输入信息有误,请重新输入\n");
			continue;
		}

	}

	struct LoginMsg msg;
	msg.id = LOGIN_MSG;
	status = STUS_WAIT_LOGIN_RES;
	strcpy(msg.qq, qq);
	tcpSend(sock, (const char *)&msg, sizeof(msg));
	mainProc(); //进入主处理程序
	return;
}

void procLoginMsgResponse(struct LoginMsgResponse *msg)
{
	if (msg->isOK == 1)
	{
		printMsg("登录成功!\n");
		status = STUS_LOGINED;//已登录状态
	}
	else
	{
		printMsg("登录失败!\n");
		printMsgExit(msg->reason);
		printf("\n");
	}
}

void procFriendQqMsgResponse(struct FriendQqMsgResponse *msg)
{
	if (msg->isOK == 1)
	{
		printMsg("好友目前在线,可以开始聊天...\n");
		status = STUS_TALK;
	}
	else
	{
		printMsg("好友不存在啊,再换个人试试!\n");
		status = STUS_LOGINED;
	}
}

void procTalkMsg(struct TalkMsg *msg)
{
	char buf[1024] = { 0 };

	if (strcmp(msg->qq, fqq) == 0)
	{//表示是自己发起的聊天,仅仅显示信息即可
		printf("\n");
		sprintf(buf, "%s说>>%s", fqq, msg->info);
		printMsg(buf);
	}
	else
	{//是陌生人发起的聊天
		printf("\n");
		sprintf(buf, "%s说>>%s", msg->qq, msg->info);
		printMsg(buf);
	}
}

void procApplyAllFriend(struct AllFriendMsg *msg)
{<pre name="code" class="html">#pragma once
/************************************************************
*  文件名:TalkClientService.h
*  描述:  客户端业务层函数声明
*************************************************************/
#ifndef _TALKCLIENTSERVICE_H_
#define _TALKCLIENTSERVICE_H_
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "MyMsg.h"

void connectServer();
void procLoginMsgResponse(struct LoginMsgResponse *msg);
void procFriendQqMsgResponse(struct FriendQqMsgResponse *msg);
void procTalkMsg(struct TalkMsg *msg);
void statusConnected();
void statusLogined();
void statusTalk();
void procApplyAllFriend(struct AllFriendMsg *msg);

/** 客户端状态 **/
enum {
	STUS_START,
	STUS_CONNECTED,
	STUS_WAIT_LOGIN_RES,
	STUS_LOGINED,
	STUS_WAIT_QUERY_FQQ_RES,
	STUS_TALK,
	STUS_WAIT_QUERY_ALLQQ_RES
};

#endif

char buf[100] = { 0 };sprintf(buf, "%s", msg->qq);printMsg("在线的QQ好友: \n");printMsg(buf);printf("\n");status = STUS_LOGINED;}
 
 

TalkClientService.h


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值