#ifndef _CLIENT_LINK_LIST_H_
#define _CLIENT_LINK_LIST_H_
#include <WinSock2.h>
#include <stdio.h>
//客户端信息结构体
typedef struct _Client
{
SOCKET sClient; //客户端套接字
char buf[128]; //数据缓冲区
char userName[16]; //客户端用户名
char IP[20]; //客户端IP
unsigned short Port; //客户端端口
UINT_PTR flag; //标记客户端,用来区分不同的客户端
char ChatName[16]; //指定要和哪个客户端聊天
_Client* next; //指向下一个结点
}Client, *pClient;
/* * function 初始化链表 * return 无返回值 */
void Init();
/* * function 获取头节点 * return 返回头节点 */
pClient GetHeadNode();
/* * function 添加一个客户端 * param client表示一个客户端对象 * return 无返回值 */
void AddClient(pClient client);
/* * function 删除一个客户端 * param flag标识一个客户端对象 * return 返回true表示删除成功,false表示失败 */
bool RemoveClient(UINT_PTR flag);
/* * function 根据name查找指定客户端 * param name是指定客户端的用户名 * return 返回一个client表示查找成功,返回INVALID_SOCKET表示无此用户 */
SOCKET FindClient(char* name);
/* * function 根据SOCKET查找指定客户端 * param client是指定客户端的套接字 * return 返回一个pClient表示查找成功,返回NULL表示无此用户 */
pClient FindClient(SOCKET client);
/* * function 计算客户端连接数 * param client表示一个客户端对象 * return 返回连接数 */
int CountCon();
/* * function 清空链表 * return 无返回值 */
void ClearClient();
/* * function 检查连接状态并关闭一个连接 * return 返回值 */
void CheckConnection();
/* * function 指定发送给哪个客户端 * param FromName,发信人 * param ToName, 收信人 * param data, 发送的消息 */
void SendData(char* FromName, char* ToName, char* data);
#endif //_CLIENT_LINK_LIST_H_
#include "ClientLinkList.h"
pClient head = (pClient)malloc(sizeof(_Client)); //创建一个头结点
/* * function 初始化链表 * return 无返回值 */
void Init()
{
head->next = NULL;
}
/* * function 获取头节点 * return 返回头节点 */
pClient GetHeadNode()
{
return head;
}
/* * function 添加一个客户端 * param client表示一个客户端对象 * return 无返回值 */
void AddClient(pClient client)
{
client->next = head->next; //比如:head->1->2,然后添加一个3进来后是
head->next = client; //3->1->2,head->3->1->2
}
/* * function 删除一个客户端 * param flag标识一个客户端对象 * return 返回true表示删除成功,false表示失败 */
bool RemoveClient(UINT_PTR flag)
{
//从头遍历,一个个比较
pClient pCur = head->next;//pCur指向第一个结点
pClient pPre = head; //pPre指向head
while (pCur)
{
// head->1->2->3->4,要删除2,则直接让1->3
if (pCur->flag == flag)
{
pPre->next = pCur->next;
closesocket(pCur->sClient); //关闭套接字
free(pCur); //释放该结点
return true;
}
pPre = pCur;
pCur = pCur->next;
}
return false;
}
/* * function 查找指定客户端 * param name是指定客户端的用户名 * return 返回socket表示查找成功,返回INVALID_SOCKET表示无此用户 */
SOCKET FindClient(char* name)
{
//从头遍历,一个个比较
pClient pCur = head;
while (pCur = pCur->next)
{
if (strcmp(pCur->userName, name) == 0)
return pCur->sClient;
}
return INVALID_SOCKET;
}
/* * function 根据SOCKET查找指定客户端 * param client是指定客户端的套接字 * return 返回一个pClient表示查找成功,返回NULL表示无此用户 */
pClient FindClient(SOCKET client)
{
//从头遍历,一个个比较
pClient pCur = head;
while (pCur = pCur->next)
{
if (pCur->sClient == client)
return pCur;
}
return NULL;
}
/* * function 计算客户端连接数 * param client表示一个客户端对象 * return 返回连接数 */
int CountCon()
{
int iCount = 0;
pClient pCur = head;
while (pCur = pCur->next)
iCount++;
return iCount;
}
/* * function 清空链表 * return 无返回值 */
void ClearClient()
{
pClient pCur = head->next;
pClient pPre = head;
while (pCur)
{
//head->1->2->3->4,先删除1,head->2,然后free 1
pClient p = pCur;
pPre->next = p->next;
free(p);
pCur = pPre->next;
}
}
/* * function 检查连接状态并关闭一个连接 * return 返回值 */
void CheckConnection()
{
pClient pclient = GetHeadNode();
while (pclient = pclient->next)
{
if (send(pclient->sClient, "", sizeof(""), 0) == SOCKET_ERROR)
{
if (pclient->sClient != 0)
{
printf("Disconnect from IP: %s,UserName: %s\n", pclient->IP, pclient->userName);
char error[128] = { 0 }; //发送下线消息给发消息的人
sprintf(error, "The %s was downline.\n", pclient->userName);
send(FindClient(pclient->ChatName), error, sizeof(error), 0);
closesocket(pclient->sClient); //这里简单的判断:若发送消息失败,则认为连接中断(其原因有多种),关闭该套接字
RemoveClient(pclient->flag);
break;
}
}
}
}
/* * function 指定发送给哪个客户端 * param FromName,发信人 * param ToName, 收信人 * param data, 发送的消息 */
void SendData(char* FromName, char* ToName, char* data)
{
SOCKET client = FindClient(ToName); //查找是否有此用户
char error[128] = { 0 };
int ret = 0;
if (client != INVALID_SOCKET && strlen(data) != 0)
{
char buf[128] = { 0 };
sprintf(buf, "%s: %s", FromName, data); //添加发送消息的用户名
ret = send(client, buf, sizeof(buf), 0);
}
else//发送错误消息给发消息的人
{
if(client == INVALID_SOCKET)
sprintf(error, "The %s was downline.\n", ToName);
else
sprintf(error, "Send to %s message not allow empty, Please try again!\n", ToName);
send(FindClient(FromName), error, sizeof(error), 0);
}
if (ret == SOCKET_ERROR)//发送下线消息给发消息的人
{
sprintf(error, "The %s was downline.\n", ToName);
send(FindClient(FromName), error, sizeof(error), 0);
}
}
/*
#include <WinSock2.h>
#include <process.h>
#include <stdlib.h>
#include "ClientLinkList.h"
#pragma comment(lib,"ws2_32.lib")
SOCKET g_ServerSocket = INVALID_SOCKET; //服务端套接字
SOCKADDR_IN g_ClientAddr = { 0 }; //客户端地址
int g_iClientAddrLen = sizeof(g_ClientAddr);
typedef struct _Send
{
char FromName[16];
char ToName[16];
char data[128];
}Send,*pSend;
//发送数据线程
unsigned __stdcall ThreadSend(void* param)
{
pSend psend = (pSend)param; //转换为Send类型
SendData(psend->FromName, psend->ToName, psend->data); //发送数据
return 0;
}
//接受数据
unsigned __stdcall ThreadRecv(void* param)
{
int ret = 0;
while (1)
{
pClient pclient = (pClient)param;
if (!pclient)
return 1;
ret = recv(pclient->sClient, pclient->buf, sizeof(pclient->buf), 0);
if (ret == SOCKET_ERROR)
return 1;
if (pclient->buf[0] == '#' && pclient->buf[1] != '#') //#表示用户要指定另一个用户进行聊天
{
SOCKET socket = FindClient(&pclient->buf[1]); //验证一下客户是否存在
if (socket != INVALID_SOCKET)
{
pClient c = (pClient)malloc(sizeof(_Client));
c = FindClient(socket); //只要改变ChatName,发送消息的时候就会自动发给指定的用户了
memset(pclient->ChatName, 0, sizeof(pclient->ChatName));
memcpy(pclient->ChatName , c->userName,sizeof(pclient->ChatName));
}
else
send(pclient->sClient, "The user have not online or not exits.",64,0);
continue;
}
pSend psend = (pSend)malloc(sizeof(_Send));
//把发送人的用户名和接收消息的用户和消息赋值给结构体,然后当作参数传进发送消息进程中
memcpy(psend->FromName, pclient->userName, sizeof(psend->FromName));
memcpy(psend->ToName, pclient->ChatName, sizeof(psend->ToName));
memcpy(psend->data, pclient->buf, sizeof(psend->data));
_beginthreadex(NULL, 0, ThreadSend, psend, 0, NULL);
Sleep(200);
}
return 0;
}
//开启接收消息线程
void StartRecv()
{
pClient pclient = GetHeadNode();
while (pclient = pclient->next)
_beginthreadex(NULL, 0, ThreadRecv, pclient, 0, NULL);
}
//管理连接
unsigned __stdcall ThreadManager(void* param)
{
while (1)
{
CheckConnection(); //检查连接状况
Sleep(2000); //2s检查一次
}
return 0;
}
//接受请求
unsigned __stdcall ThreadAccept(void* param)
{
_beginthreadex(NULL, 0, ThreadManager, NULL, 0, NULL);
Init(); //初始化一定不要再while里面做,否则head会一直为NULL!!!
while (1)
{
//创建一个新的客户端对象
pClient pclient = (pClient)malloc(sizeof(_Client));
//如果有客户端申请连接就接受连接
if ((pclient->sClient = accept(g_ServerSocket, (SOCKADDR*)&g_ClientAddr, &g_iClientAddrLen)) == INVALID_SOCKET)
{
printf("accept failed with error code: %d\n", WSAGetLastError());
closesocket(g_ServerSocket);
WSACleanup();
return -1;
}
recv(pclient->sClient, pclient->userName, sizeof(pclient->userName), 0); //接收用户名和指定聊天对象的用户名
recv(pclient->sClient, pclient->ChatName, sizeof(pclient->ChatName), 0);
memcpy(pclient->IP, inet_ntoa(g_ClientAddr.sin_addr), sizeof(pclient->IP)); //记录客户端IP
pclient->flag = pclient->sClient; //不同的socke有不同UINT_PTR类型的数字来标识
pclient->Port = htons(g_ClientAddr.sin_port);
AddClient(pclient); //把新的客户端加入链表中
printf("Successfuuly got a connection from IP:%s ,Port: %d,UerName: %s , ChatName: %s\n",
pclient->IP, pclient->Port, pclient->userName,pclient->ChatName);
if (CountCon() >= 2) //当至少两个用户都连接上服务器后才进行消息转发
StartRecv();
Sleep(2000);
}
return 0;
}
//启动服务器
int StartServer()
{
//存放套接字信息的结构
WSADATA wsaData = { 0 };
SOCKADDR_IN ServerAddr = { 0 }; //服务端地址
USHORT uPort = 18000; //服务器监听端口
//初始化套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
return -1;
}
//判断版本
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("wVersion was not 2.2\n");
return -1;
}
//创建套接字
g_ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (g_ServerSocket == INVALID_SOCKET)
{
printf("socket failed with error code: %d\n", WSAGetLastError());
return -1;
}
//设置服务器地址
ServerAddr.sin_family = AF_INET;//连接方式
ServerAddr.sin_port = htons(uPort);//服务器监听端口
ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//任何客户端都能连接这个服务器
//绑定服务器
if (SOCKET_ERROR == bind(g_ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
{
printf("bind failed with error code: %d\n", WSAGetLastError());
closesocket(g_ServerSocket);
return -1;
}
//设置监听客户端连接数
if (SOCKET_ERROR == listen(g_ServerSocket, 20000))
{
printf("listen failed with error code: %d\n", WSAGetLastError());
closesocket(g_ServerSocket);
WSACleanup();
return -1;
}
_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, 0);
for (int k = 0;k < 100;k++) //让主线程休眠,不让它关闭TCP连接.
Sleep(10000000);
//关闭套接字
ClearClient();
closesocket(g_ServerSocket);
WSACleanup();
return 0;
}
int main()
{
StartServer(); //启动服务器
return 0;
}
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#pragma comment(lib,"ws2_32.lib")
#define RECV_OVER 1
#define RECV_YET 0
char userName[16] = { 0 };
char chatName[16] = { 0 };
int iStatus = RECV_YET;
//接受数据
unsigned __stdcall 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 __stdcall ThreadSend(void* param)
{
char buf[128] = { 0 };
int ret = 0;
while (1)
{
int c = getch();
if (c == 27) //ESC ASCII是27
{
memset(buf, 0, sizeof(buf));
printf("Please input the chat name:");
gets_s(buf);
char b[17] = { 0 };
sprintf(b, "#%s", buf);
ret = send(*(SOCKET*)param,b , sizeof(b), 0);
if (ret == SOCKET_ERROR)
return 1;
continue;
}
if(c == 72 || c == 0 || c == 68)//为了显示美观,加一个无回显的读取字符函数
continue; //getch返回值我是经过实验得出如果是返回这几个值,则getch就会自动跳过,具体我也不懂。
printf("%s: ", userName);
gets_s(buf);
ret = send(*(SOCKET*)param, buf, sizeof(buf), 0);
if (ret == SOCKET_ERROR)
return 1;
}
return 0;
}
//连接服务器
int ConnectServer()
{
WSADATA wsaData = { 0 };//存放套接字信息
SOCKET ClientSocket = INVALID_SOCKET;//客户端套接字
SOCKADDR_IN ServerAddr = { 0 };//服务端地址
USHORT uPort = 18000;//服务端端口
//初始化套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
return -1;
}
//判断套接字版本
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("wVersion was not 2.2\n");
return -1;
}
//创建套接字
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ClientSocket == INVALID_SOCKET)
{
printf("socket failed with error code: %d\n", WSAGetLastError());
return -1;
}
//输入服务器IP
printf("Please input server IP:");
char IP[32] = { 0 };
gets_s(IP);
//设置服务器地址
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(uPort);//服务器端口
ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP);//服务器地址
printf("connecting......\n");
//连接服务器
if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
{
printf("connect failed with error code: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return -1;
}
printf("Connecting server successfully IP:%s Port:%d\n",
IP, htons(ServerAddr.sin_port));
printf("Please input your UserName: ");
gets_s(userName);
send(ClientSocket, userName, sizeof(userName), 0);
printf("Please input the ChatName: ");
gets_s(chatName);
send(ClientSocket, chatName, sizeof(chatName), 0);
printf("\n\n");
_beginthreadex(NULL, 0, ThreadRecv, &ClientSocket, 0, NULL); //启动接收和发送消息线程
_beginthreadex(NULL, 0, ThreadSend, &ClientSocket, 0, NULL);
for (int k = 0;k < 1000;k++)
Sleep(10000000);
closesocket(ClientSocket);
WSACleanup();
return 0;
}
int main()
{
ConnectServer(); //连接服务器
return 0;
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有