C语言 SOCKET 基于TCP协议的多人聊天室

网上几乎找不到合适的C语言SOCKET代码,很多都是十几年前的了。老师布置了这个作业自己调试通过了,但是软件只能用VC6++
软件我会传到网盘,和这个代码文件一起。vc6++使用方法可以自行查阅一下。
效果图在最后
先赞后看,养成习惯
在这里插入图片描述

服务端:

// socket server.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"
#include "winsock2.h"  //winsock相关函数头文件
#include "string.h"
#pragma comment(lib,"ws2_32.lib")  //winsock链接库文件


//客户端结构体
typedef struct socket
{
	SOCKET client;//客户端套接字
	char username[16];//客户名
	char buf[256];//消息拼接缓存
	int flag;//当前客户端标号
}NewSOCKET;

//最大设置为10人连接
NewSOCKET sClient[10];

//当前客户端的标记
int count=0;

//接收消息与转发消息
DWORD WINAPI AnswerThread(LPVOID lparam)
{
	NewSOCKET *Client=(NewSOCKET *)lparam;
	char revData[128];
	int i=0;
	char temp[2]=":";
	while (true)
	{
        //接收数据
		int ret = recv(Client->client, revData, 128, 0);
		if(ret > 0)
		{
			//将用户名、“:”和消息拼接成一个字符串
			strcpy(Client->buf, Client->username);
			strcat(Client->buf, temp);
            strcat(Client->buf, revData);
			//给除自己外的其他客户端发送数据
			for(i=0;i<count;i++)
			{
				if(i!=Client->flag)
					send(sClient[i].client,Client->buf, strlen(Client->buf), 0);
			}
		}
	}
    closesocket(Client->client);
	printf("线程号%d: 我结束了\n",GetCurrentThreadId());
	return 0;
}

int main(int argc, char* argv[])
{
    //winsock初始化
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        return 0;
    }

    //socket()
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

    //设置IP和port
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(18888);
    sin.sin_addr.S_un.S_addr = INADDR_ANY; 
    
    //bind()
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error !");
    }

    //listen()
    if(listen(slisten, 5) == SOCKET_ERROR)
    {
        printf("listen error !");
        return 0;
    }

    //accept()
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr); 
    printf("线程号%d: 初始化完成,服务器等待连接...\n",GetCurrentThreadId());
    while (true)
    {
        sClient[count].client = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);//接受客户端
		sClient[count].flag=count;
		recv(sClient[count].client, sClient[count].username, sizeof(sClient[count].username), 0); //接收用户名
		
        if(sClient[count].client == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
        printf("线程号%d: 接受到一个连接:%s:%d 用户名:%s \r\n", GetCurrentThreadId(), inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port),sClient[count].username);
		DWORD  dwThreadId;  
        HANDLE  hThread;  
        //创建线程处理消息接收与转发              
		hThread=CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)AnswerThread,&sClient[count],0,&dwThreadId);
		if(hThread==NULL)  
		{  
			printf("线程号%d: 创建线程出错\n", GetCurrentThreadId());  
		}  
		else  
		{  
			printf("线程号%d: 已创建线程(线程号%d)处理当前连接,服务器继续等待新连接...\n", GetCurrentThreadId(),dwThreadId);  
			CloseHandle(hThread);
		}
		//标记加一
		count++;
		
    }
    
    //closesocket()
    closesocket(slisten);
    
    //winsock注销
    WSACleanup();
    return 0;
}





客户端

// socket client.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "winsock2.h"  //winsock相关函数头文件
#include <conio.h>
#pragma comment(lib,"ws2_32.lib")  //winsock链接库文件

#define RECV_OVER 1
#define RECV_YET 0
char userName[16] = { 0 };
int iStatus = RECV_YET;
//接受数据
unsigned  ThreadRecv(void* param)
{
	char buf[128] = { 0 };
	while (1)
	{
		int ret = recv(*(SOCKET*)param, buf, sizeof(buf), 0);
		if (ret == SOCKET_ERROR)
		{
			Sleep(500);
			continue;
		}
		if (strlen(buf) != 0)
		{
			printf("%s\n", buf);
			iStatus = RECV_OVER;
		}
		else
			Sleep(100);   
			
		
	}
	return 0;
}

//发送数据
unsigned  ThreadSend(void* param)
{
	char buf[128] = { 0 };
	int ret = 0;
	while (1)
	{
		int c = getch();//为了显示美观,加一个无回显的读取字符函数读取回车
		if(c == 72 || c == 0 || c == 68)
			continue;                  
		printf("%s: ", userName);
		gets(buf);
		ret = send(*(SOCKET*)param, buf, sizeof(buf), 0);
		if (ret == SOCKET_ERROR)
			return 1;
	}
	return 0;
}

//连接服务器
int ConnectServer()
{
	//初始化套接字
	WORD sockVersion = MAKEWORD(2,2);
    WSADATA data; 
    if(WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    //socket()
    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sclient == INVALID_SOCKET)
    {
        printf("invalid socket !");
        return 0;
    }
	
	//设置服务器地址
    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(18888);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 

	printf("connecting......\n");
	//连接服务器
	if (SOCKET_ERROR == connect(sclient, (SOCKADDR*)&serAddr, sizeof(serAddr)))
	{
		printf("connect failed with error code: %d\n", WSAGetLastError());
		closesocket(sclient);
		WSACleanup();
		return -1;
	}
	printf("You have been in the room\n");
	//获取用户名
	printf("Please input your UserName: ");
	gets(userName);
	send(sclient, userName, sizeof(userName), 0);
	printf("\n\n");
	DWORD  dwThreadId1,dwThreadId2;  
    HANDLE  hThread1,hThread2;  
    //开启接受线程和发送线程                   
	hThread1=CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadRecv,&sclient,0,&dwThreadId1);
	hThread2=CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadSend,&sclient,0,&dwThreadId2);
	//关闭句柄
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	//循环很久防止主线程退出
	for (int k = 0;k < 1000;k++)
		Sleep(10000000);
	closesocket(sclient);
	WSACleanup();
	return 0;
}

int main()
{
	ConnectServer(); //连接服务器
	return 0;
}

代码以及VC6++软件客户端演示,输入用户名后就连接成功了,每次输入消息前敲一下回车会出现自己的名字,接下来输入信息再敲一次回车即可发送消息
服务端不用输入什么,只是转发消息和显示连接

链接:https://pan.baidu.com/s/1et0w9ZceMpUO8oppZd3odg
提取码:g37s

代码方面有什么不懂可以留言,但我不一定能解答。
在这里插入图片描述

  • 13
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
一、 系统概要 1、 开发平台: Windows XP, Visual C++ 6.0 2、 系统简单描述: 这是一个用VC做的简单的聊天系统。在此系统中,采用TCP协议,程序分为服务器端各客户端。系统能实现简单的聊天功能包括一对多,而且同时也支持一对一,即私聊功能。在系统运行中,用户可以随时更改自己的用户名。功能虽然单一但也能够满足聊天的基本功能。 二、 通信规范的制作 程序中定义了一个结构体MYMESSAGE来作为信息传送的载体 struct MESSAGE { char flag; //作为标志来区别所发送的信息; char data[100];//发送的内容; char addr[25]; //客户IP地址和端口号 }; 三、 主要模块的设计分析 服务器端: 系统流程如下: 设计思路: 基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和用户端两部分。设计思路(VC6.0下): 第一部分 服务器端 一、创建服务器套接字(create)。 二、服务器套接字进行信息绑定(bind),并开始监听连接(listen)。 三、接受来自用户端的连接请求(accept)。 四、开始数据传输(send/receive)。 五、关闭套接字(closesocket)。 第二部分 客户端 一、创建客户套接字(create)。 二、与远程服务器进行连接(connect),如被接受则创建接收进程。 三、开始数据传输(send/receive)。 四、关闭套接字(closesocket)。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值