⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatserver.c

📁 实现多线程聊天室
💻 C
字号:
// 我真诚地保证:
    
// 由于技术加时间的原因,我虽然没有完全独立的把整个程序设计出来,但是通过参考上课笔记和
// 同学的源程序我已经把整个程序的流程和细节都搞清楚,并且最终完成了整个程序。
// 如果在上述过程中,我遇到了什么困难而求教于人,那么,我将在程序实习报告中
// 详细地列举我所遇到的问题,以及别人给我的提示。

// 在此,我感谢吴仁海,鲍承会同学对我的启发和帮助。下面的报告中,我还会具体地提到
// 他们在各个方法对我的帮助。
 
// 我的程序里中凡是引用到其他程序或文档之处,
// 例如教材、课堂笔记、网上的源代码以及其他参考书上的代码段,
// 我都已经在程序的注释里很清楚地注明了引用的出处。

// 我从未没抄袭过别人的程序,也没有盗用别人的程序,
// 不管是修改式的抄袭还是原封不动的抄袭。

// 我编写这个程序,从来没有想过要去破坏或妨碍其他计算机系统的正常运转。
    
// 陈友元(01011105)
//文件名称:chatserver.c
//项目名称:多线程聊天室
//创建者:陈友元(01011105)
//创建时间:2004-5-31
//最后修改时间:2004-6-3
//功能: 接受客户端发来的信息
//文件中的函数名称和简单功能描述:
//文件中定义的全局变量和简单功能描述:
//文件中用到的他处定义的全局变量及其出处:
//与其他文件的依赖关系:sock_common.h定义了错误信息



/*以下程序为服务器端程序,通过使用多线程(该程序设置为最多5个线程)
来连接客户端套接字,从而接受客户端发来的信息,并把信息发送给其他的用户*/
#include "sock_common.h"
#include <conio.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libcmt.lib")
#define BUFFER_SIZE    500//定义缓冲区大小为500
unsigned __stdcall ProcessThread(void *  p);
unsigned long hThreadHandle;
unsigned uThreadID;
static SOCKET chatsock[5];//定义大小为五的套接字树组用来保存连接到服务器上的客户端套接字,每一个套接字对应一个聊天室的人。
static char chatip[5][20];//定义5*20的二维数组,用来保存参加聊天的客户端IP
static int chatcount = 0;//初始聊天人数为0,该变量也用来标室聊天者
int do_something_with(SOCKET NewConnection);
void main(int argc, char *argv[])
{
	WSADATA              wsaData;
	SOCKET               ListeningSocket;//监听套接字
	SOCKET               NewConnection;//申请连接的套接字
	SOCKADDR_IN          ServerAddr;//服务器地址
	SOCKADDR_IN          ClientAddr;//客户机地址
	int                  ClientAddrLen;//客户机地址长度
	u_short              Port = 5150;//默认断口号为5150
	int                  Ret;//函数调用时返回值
	/*****参考上课笔记********/
	//初试化低层的Windous Socket DLL
	if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
	{
		printf("WSAStartup failed with error %d\n", Ret);
		return;
	}
    //创建新的socket以监听客户端的连接
	if ((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		sockerror("Create socket failed! ");
		WSACleanup();
		return;
	} 
	ServerAddr.sin_family = AF_INET;/*ADDRESS FAMILY*/
	ServerAddr.sin_port = htons(Port);/*PORT NUMBER*/    
	ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);/*INTERNET ADDRESS*/
	//把socket和机器上的特定端口连接起来
	if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
	{
		sockerror("Bind failed! ");
		closesocket(ListeningSocket);
		WSACleanup();
		return;
	}
	//为申请进入的连接建立一个后备日志,然后就可用accept()接受连接了,5为等待连接的最大长度
	if (listen(ListeningSocket, 5) == SOCKET_ERROR)
	{
		sockerror("Liten failed! ");
		closesocket(ListeningSocket);
		WSACleanup();
		return;
	} 
	while(!kbhit())
	{
		//接受新的连接
		ClientAddrLen = sizeof (ClientAddr);
		if ((NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen)) == INVALID_SOCKET)
		{
			sockerror("Accept socket failed! ");
			closesocket(ListeningSocket);
			WSACleanup();
			return;
		}
		
		if(chatcount < 5){
			chatsock[chatcount] = NewConnection;//将新接收的客户端套接字保存入服务器端的套接字数组
			strcpy(chatip[chatcount], inet_ntoa(ClientAddr.sin_addr));//将客户端的numbers-and-dots
		                                                              //格式的IP地址转换成unsigned long
			                                                          //并保存
			chatcount++;//聊天人数加一
		}
		else{
			printf("Cant chat ,too many people\n");//如果聊天数已经超过5则不予操作,并提示信息
		}
		//创建并初始化一个线程,该线程和新接收socket连接
		hThreadHandle = _beginthreadex(NULL,0,ProcessThread,(void *)&NewConnection,0,&uThreadID);
		CloseHandle((HANDLE) hThreadHandle);
	}
	closesocket(ListeningSocket);//把套接字从拥有对象参考表中取消
	WSACleanup();//从底层的Windows Sockets DLL中撤消注册
}
unsigned __stdcall ProcessThread(void *  p)//多线程调用
{
	SOCKET connection = *((SOCKET *) p);
	do_something_with(connection);//对该套接字进行操作
	closesocket(connection);
	return 0;
}
int do_something_with(SOCKET NewConnection)
{
	SOCKADDR_IN    ClientIp;//客户机地址
	char pBuffer[BUFFER_SIZE];
	char infomation[BUFFER_SIZE];
	char* ipname;//客户端名称指针
	int len = sizeof(ClientIp), infolen;
	int Ret;//返回值
	int i;//给其他客户机发送信息时的循环变量
	while(1)
	{
		Ret = recv(NewConnection,pBuffer,BUFFER_SIZE,0);
		if (Ret <= 0)
			return Ret;//如果接收失败则退出
		getpeername(NewConnection, &ClientIp, &len);//从客户端套接字中获得IP
		ipname = inet_ntoa(ClientIp.sin_addr);//将客户端的numbers-and-dots
		                                      //格式的IP地址转换成unsigned long
			                                  //并把指针赋给ipname
		sprintf(infomation, "\nmessage from  <%s> :\n",ipname);//提示信息来自哪个客户端
		infolen = strlen(infomation);
		//在服务器上显示聊天信息
		printf(infomation);//客户机名
		pBuffer[Ret] = '\0';
		printf(pBuffer);//聊天记录
		printf("\n-------------------------------------\n");
		//向其他客户机发送聊天记录,如果是当前说话者的socket则不发送
		for(i = 0; i < chatcount; i++){
			if(chatsock[i] != NewConnection){
				infolen = send(chatsock[i], infomation, infolen, 0);//发送说话客户机名
				Ret = send(chatsock[i], pBuffer, Ret, 0);//发送说话内容
			}
		}
	}
	return 1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -