计算机网络-多人聊天编程实验

【实验题目】多人聊天编程实验
【实验目的】掌握套节字的多线程编程方法。
【实验介绍】利用客户/服务器(Client/Sever或CS)模式实现一个多人聊天(群聊)程序。其功能是每个客户发送给服务器的消息都会传送给所有的客户端。

【实验环境】
采用Windows VC++控制台编程,建立新项目的方法:选择菜单“文件/新建项目/Win32控制台应用程序/空项目”,然后增加CPP空文件,拷贝源程序。集成环境使用VS2012或更高版本。

【实验内容】

(1)编写多人聊天程序,要求客户端和服务器都采用多线程方式进行编程。每个客户端都采用TCP协议连接服务器并保持连接。服务器同时与所有客户端建立和保持连接。每个客户端输入的消息都会通过服务器转发给所有客户。

(2)服务器程序转发某个客户端发来的消息时都在消息前面加上该客户端的IP地址和端口号以及服务器的当前时间。要求服务器程序把转发的消息也显示出来。

(3)新客户刚连接时服务器端把“enter”消息(包含客户端IP地址和端口号)发送给所有客户端。

(4)客户端输入exit时退出客户端程序(正常退出),或者客户端直接关闭窗口退出(异常退出),服务器都会把该客户leave的消息广播给所有客户。

客户端程序

#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <process.h>
#include <math.h>

#define    BUFLEN        2000                  // 缓冲区大小
#define WSVERS        MAKEWORD(2, 0)        // 指明版本2.0 
#pragma comment(lib,"ws2_32.lib")         // 指明winsock 2.0 Llibrary

/*------------------------------------------------------------------------
 * main - TCP client for DAYTIME service
 *------------------------------------------------------------------------
 */

SOCKET    sock, sockets[100] = { NULL };                          /* socket descriptor            */
//    int    cc;                                /* recv character count            */
char    *packet = NULL;               /* buffer for one line of text    */
char *pts, *input;
HANDLE hThread;
unsigned threadID;

unsigned int __stdcall Chat(PVOID PM)
{
	time_t    now;
	(void)time(&now);
	pts = ctime(&now);
	char buf[2000];

	while (1)
	{
		int cc = recv(sock, buf, BUFLEN, 0);   //cc为接收的字符数
		if (cc == SOCKET_ERROR || cc == 0)
		{
			printf("Error: %d.----", GetLastError());
			printf("与服务器断开连接!\n");
			CloseHandle(hThread);
			(void)closesocket(sock);
			break;
		}
		else if (cc > 0)
		{
			//    buf[cc] = '\0';
			//printf("与服务器连接成功!\n");
			printf("%s\n", buf);

			//    printf("输入数据(exit退出):  \n");
		}
	}
	return 0;
}

int main(int argc, char *argv[])
{
	time_t    now;
	(void)time(&now);
	pts = ctime(&now);
	const char    *host = "127.0.0.1";        /* server IP to connect         */
	//const char    *host = "172.26.54.208";
	const char *service = "5050";          /* server port to connect       */
	//const char *service = "50520";
	struct  sockaddr_in sin;            /* an Internet endpoint address    */
	WSADATA wsadata;
	WSAStartup(WSVERS, &wsadata);       /* 启动某版本Socket的DLL        */

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons((u_short)atoi(service));    //atoi:把ascii转化为int. htons:主机序(host)转化为网络序(network), s--short
	sin.sin_addr.s_addr = inet_addr(host);           //如果host为域名,需要先用函数gethostbyname把域名转化为IP地址

	sock = socket(PF_INET, SOCK_STREAM, 0);

	connect(sock, (struct sockaddr *)&sin, sizeof(sin));

	printf("\t\t\t\t   客户端启动     \n");

	hThread = (HANDLE)_beginthreadex(NULL, 0, Chat, NULL, 0, &threadID);

	while (1)
	{
		char buf1[2000];

		//     scanf("%s",&buf1);
		//printf("可以聊天了\n\n");
		//printf("请输入发送内容:");
		gets_s(buf1);
		//printf("%s\n",buf1);
		if (!strcmp(buf1, "exit"))
			goto end;

		(void)send(sock, buf1, sizeof(buf1), 0);
		(void)time(&now);
		pts = ctime(&now);

		printf("发送成功!\n\n");
		//printf("时间: %s\n", pts);
	}

end:    CloseHandle(hThread);
	closesocket(sock);
	WSACleanup();                     /* 卸载某版本的DLL */

	printf("按回车键继续...");
	getchar();
	return 0;                           /* exit */
}

服务端程序

#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <time.h>
#include "conio.h"
#include <windows.h>
#include <process.h>
#include <math.h>

#define QLEN       5
#define    WSVERS    MAKEWORD(2, 0)
#define    BUFLEN    2000             // 缓冲区大小
#pragma comment(lib,"ws2_32.lib")  //winsock 2.2 library

SOCKET    msock, ssock;            /* master & slave sockets           */
SOCKET    sockets[100] = { NULL };

int cc;
char    *pts;                    /* pointer to time string           */
time_t    now;                    /* current time                       */
char buf[2000];                      /* buffer                          */
char *input;
HANDLE hThread1, hThread[100] = { NULL };
unsigned int threadID, ThreadID[100], number;

struct    sockaddr_in fsin;
struct    sockaddr_in Sin;

unsigned int __stdcall Chat(PVOID PM)
{
	char buf1[2000];
	char buf2[2000];
	char buf3[2000];
	char buf4[2000];
	(void)time(&now);
	pts = ctime(&now);
	sockets[number] = ssock;
	SOCKET    sock = ssock;
	ThreadID[number] = threadID;
	unsigned int threadid = threadID;
    
	
	sprintf(buf2, "客户【IP:%s 端口:%d】:enter  \n时间:%s\n", inet_ntoa(fsin.sin_addr), fsin.sin_port,pts);
	
	//sprintf(buf2, "Client:enter \nIP:%s \nPort:%d \ntime:%s\n", s, fsin.sin_port, pts);
	printf("%s ", buf2);
	
	for (int i = 0; i <= number; i++)
	{
		if (sockets[i] != NULL )
		{
			(void)send(sockets[i], buf2, sizeof(buf2), 0);
			
		}
	}
	printf(" \n");


flag1:cc = recv(sock, buf3, BUFLEN, 0);   //cc为接收的字符数
	 if (cc == SOCKET_ERROR || cc == 0)
	{
		(void)time(&now);
		pts = ctime(&now);
		
		sprintf(buf3, "客户【IP:%s 端口:%d】:leave !  \n时间:%s", inet_ntoa(fsin.sin_addr), fsin.sin_port, pts);
		sock = NULL;
		sockets[number] = NULL;
		CloseHandle(hThread[number]);
		printf("%s ", buf3);
		
		for (int i = 0; i <= number; i++)
		{
			if (sockets[i] != NULL && sockets[i] != sock)
			{
				(void)send(sockets[i], buf3, sizeof(buf3), 0);
				
			}
		}
		printf(" \n");
	}

	else if (cc > 0)
	{
		(void)time(&now);
		pts = ctime(&now);
		sprintf(buf4, "客户【IP:%s 端口:%d】说:%s\n时间:%s", inet_ntoa(fsin.sin_addr), fsin.sin_port,buf3, pts);
		
		printf("%s ", buf4);
		
		for (int i = 0; i <= number; i++)
		{
			if (sockets[i] != NULL)
			{
				(void)send(sockets[i], buf4, sizeof(buf4), 0);
				
			}
		}
		printf(" \n");

		goto flag1;
	}
	(void)closesocket(sock);

	return 0;
}


/*------------------------------------------------------------------------
 * main - Iterative TCP server for DAYTIME service
 *------------------------------------------------------------------------
 */
void main(int argc, char *argv[])
/* argc: 命令行参数个数, 例如:C:\> TCPdaytimed 8080
					 argc=2 argv[0]="TCPdaytimed",argv[1]="8080" */
{
	int     alen;                    /* from-address length               */
	WSADATA wsadata;
	const char    *service = "5050";
	WSAStartup(WSVERS, &wsadata);                         //加载 winsock 2.2 library
	msock = socket(PF_INET, SOCK_STREAM, 0);              //生成套接字。TCP协议号=6, UDP协议号=17
	memset(&Sin, 0, sizeof(Sin));
	Sin.sin_family = AF_INET;
	Sin.sin_addr.s_addr = INADDR_ANY;                    //指定绑定接口的IP地址。INADDR_ANY表示绑定(监听)所有的接口。
	Sin.sin_port = htons((u_short)atoi(service));        //atoi--把ascii转化为int,htons - 主机序(host)转化为网络序(network), s(short) 
	bind(msock, (struct sockaddr *)&Sin, sizeof(Sin)); // 绑定端口号(和IP地址)

	listen(msock, 5);                                    //队列长度为5

	printf("\t\t\t\t服务器启动 \n");
	
	
	(void)time(&now);
	pts = ctime(&now);
	printf("\t\t\t\t时间 :%s\n", pts);
	
	number = -1;
	while (1)                                    //检测是否有按键
	{
		alen = sizeof(struct sockaddr);
		ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
		number++;
		hThread[number] = (HANDLE)_beginthreadex(NULL, 0, Chat, NULL, 0, &threadID);
	}
	(void)closesocket(msock);
	WSACleanup();                         //卸载载 winsock 2.2 library
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一共包括10个以上的聊天程序版本!绝对物有所值! 为感谢大家长期的支持,我将下载所需的资源分下调为2。网络聊天程序设计(可选)  实验要求 1、分析典型网络聊天应用软件(如QQ、MSN等)的实现原理,模拟设计一套网络聊天应用程序,必须实现以下功能: ①按照C/S结构分别设计服务端程序和客户端程序; ②服务端通过图形用户界面实现服务器的控制,负责维护用户帐户和用户群,并维护用户信息、维持客户端之的端对端通信和群聊通信、适时维护用户在线信息,并能够发送广播消息。 2、增加尽可能多的功能,用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 3、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。  实验提示 1、客户端之的通信是通过服务器进行转发的,对于两个客户端,服务器需要创建两个套接字分别维持与客户端之的连接。当客户端需要向另一个客户发送消息时,它首先将消息发送到服务器,由服务器根据目标用户帐户转发到目标主机。 2、群聊是采用多播技术实现的,也可以采用单播技术实现,但是服务器开销会增加。具体说来,若采用组播技术,当服务端收到来自一个客户端的消息后,向预先分配的该组组播地址转发该消息。若采用单播技术,服务端需要向该组内的所有客户端一一转发该消息。 3、广播消息通过广播方式发送由服务端创建的消息。 4、服务端根据客户的连接和断开情况,实时向其它客户端发送用户在线信息。 实验题目二:自选网络通信程序设计(可选)  实验要求 可以自选与网络通信相关的设计题目,要求如下: 1、在确定实验题目、设计内容以及设计功能指标要求后,向实验指导教师提交书面申请,由实验指导教师根据所选实验题目的难度和工作量确定立题后方能开始实验。 2、选择的实验题目必须具有一定综合性,并能够利用网络通信原理加以解决,同时需要具备一定的工作量。 3、设计的结果要求用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 4、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。 5、严禁抄袭别人成果,但可以部分借鉴。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值