104.tcp多线程读写实现群聊
客户端:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <winsock.h>
#include <process.h>
#pragma comment(lib,"ws2_32.lib") #define port 5529
#define ip_addr "192.168.1.108" //客户端写的线程
void write(void *p)
{
//指针类型转换
SOCKET client = (SOCKET)p;
while ()
{
printf("请输入发送的信息:\n");
char str[] = { };
scanf("%s", str);
//发送
send(client, str, strlen(str), );
Sleep();
}
} void main()
{
//对比版本
WSADATA WSA;
//客户端套接字
SOCKET client;
//服务器地址
struct sockaddr_in severaddr;
int addrlength = ;
HANDLE hthread = NULL;//线程句柄
int Ret = ;;
char senbuf[] = { }; //对比版本
if (WSAStartup(MAKEWORD(,),&WSA)!=)
{
puts("版本不一致,通信失败");
system("pause");
return;
}
//创建socket通信
client = socket(AF_INET, SOCK_STREAM, );
if (client == INVALID_SOCKET)
{
puts("客户端创建失败");
system("pause");
}
//设置服务器信息
//协议族
severaddr.sin_family = AF_INET;
//设置地址
severaddr.sin_addr.s_addr = inet_addr(ip_addr);
//设置端口
severaddr.sin_port = htons(port);
//清空
memset(severaddr.sin_zero, 0x00, ); //连接到服务器
Ret = connect(client, (struct sockaddr*) &severaddr, sizeof(severaddr));
//判断是否连接成功
if (Ret!=)
{
puts("客户端连接失败");
system("pause");
}
else
{
puts("客户端连接成功");
} //开启一个写的线程
_beginthread(write, , (void*)client);
//不断接收信息
while ()
{
char receivebuf[];
memset(receivebuf, , );//清零
Ret = recv(client, receivebuf, , );
if (strlen(receivebuf)>)
{
printf("%s\n", receivebuf);
}
} //关闭客户端
closesocket(client);
WSACleanup();
}
服务器端
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <winsock.h>
#include <process.h>
#pragma comment(lib,"ws2_32.lib") //定义端口
#define port 5529
//设置本地ip
#define ip_addr "169.254.29.232"
//发送消息的缓存区
char sendbuf[] = { };
//事件
HANDLE event=NULL;
//创建互斥量
HANDLE mutex = NULL; //保存连接的客户端信息
struct ipinfo
{
SOCKET client;//客户端
struct sockaddr_in clientaddr;
}; //读取线程是实时的,写入线程是有事件响应的,服务器输入或者收到消息则向客户端发送消息 //创建线程,用于向客户端发送信息
DWORD WINAPI clientwrite(void *p)
{
//数指针类型转换
SOCKET client = ((struct ipinfo*)p)->client;
//获取连接的客户端信息
struct sockaddr_in clientaddr = ((struct ipinfo*)p)->clientaddr;
int Ret = ; //不断读取
while ()
{
//等待事件
WaitForSingleObject(event, INFINITE);
//创建互斥量
WaitForSingleObject(mutex, INFINITE);
//判断
if (strlen(sendbuf)!=)
{
Ret = send(client, sendbuf, strlen(sendbuf), );
if (Ret == || Ret == SOCKET_ERROR)
{
//判断连接的客户端是否退出
printf("%s,%d退出\n",inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
return;
}
}
ReleaseMutex(mutex);
ResetEvent(event);//手动复位
}
return ;
} //创建线程,用于读取客户端写入的信息
DWORD WINAPI clientthreadread(void *p)
{
//数指针类型转换
SOCKET client = ((struct ipinfo*)p)->client;
//获取连接的客户端信息
struct sockaddr_in clientaddr = ((struct ipinfo*)p)->clientaddr; int Ret = ;
//接收到的信息
char receivebufall[] = {};
while ()
{ char receivebuf[] = { };
//接收
Ret = recv(client, receivebuf, , );
if (Ret == ||Ret ==SOCKET_ERROR)
{
printf("%s,%d退出\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
return;
} //收到
if (strlen(receivebuf) > )
{
memset(receivebufall, , );
sprintf(receivebufall, "收到%s:来自%s %d\n", receivebuf, inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
printf("%s", receivebufall);
} //互斥量修改全局数据
WaitForSingleObject(mutex, INFINITE);
memset(sendbuf, , );
strcpy(sendbuf, receivebufall);
ReleaseMutex(mutex);
//收到消息后设置事件,向所有客户端发送消息
SetEvent(event);
}
return ;
} //创建线程
//服务器
void mains(void *p)
{
//对比版本
WSADATA WSA;
//客户端
SOCKET client, sever;
//服务器地址,和连接的客户端信息
struct sockaddr_in localeaddr, clientaddr;
//sockaddr_in的结构体大小
int addrlength = ;
//线程句柄
HANDLE hthread = NULL;
//发送和接收消息的返回值
int Ret = ;
char senbuf[] = { }; //判断版本
if (WSAStartup(MAKEWORD(, ), &WSA) != )
{
puts("版本不一致,通信失败\n");
system("pause");
return;
}
//创建服务器套接字
sever = socket(AF_INET, SOCK_STREAM, );
if (sever == INVALID_SOCKET)
{
puts("服务器创建失败\n");
system("pause");
return;
}
//设置本地的sockaddr_in
localeaddr.sin_family = AF_INET;
localeaddr.sin_addr.s_addr = inet_addr(ip_addr);
localeaddr.sin_port = htons(port);
memset(localeaddr.sin_zero, 0x00, );//清零
//socket与sockaddr_in绑定
Ret = bind(sever, (struct sockaddr*)&localeaddr, sizeof(localeaddr));
if (Ret != )
{
puts("绑定失败");
system("pause");
return;
}
//开始监听
Ret = listen(sever, );
if (Ret != )
{
puts("监听失败");
system("pause");
return;
}
puts("服务器启动\n"); while ()
{
//获取长度
addrlength = sizeof(clientaddr);
//通过套接字接受客户端连接
client = accept(sever, (struct sockaddr*) &clientaddr, &addrlength);
if (client == INVALID_SOCKET)
{
puts("接收失败");
system("pause");
return;
}
printf("客户端连接%s %d\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port); //全局变量pinfo只是起到一个中转的作用,最后结果存放在线程里面
//创建连接的客户端信息
struct ipinfo pinfo;
pinfo.client = client;
pinfo.clientaddr = clientaddr;
//开启一个写的线程
hthread = CreateThread(NULL, , clientwrite, (void*)&pinfo, , NULL);
//开启一个读的线程
hthread = CreateThread(NULL, , clientthreadread, (void*)&pinfo, , NULL);
} closesocket(sever);
closesocket(client);
WSACleanup();
} void main()
{
event = CreateEvent(NULL, TRUE, FALSE, NULL);
mutex = CreateMutex(NULL, FALSE, NULL);//排斥
_beginthread(mains, , NULL);
while ()
{
printf("请输入向客户端发送的信息:");
scanf("%s", sendbuf);
SetEvent(event);
} system("pause");
}
104.tcp多线程读写实现群聊的更多相关文章
- 102.tcp实现多线程连接与群聊
协议之间的关系 socket在哪 socket是什么 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP ...
- Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊
分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...
- Android 基于TCP多线程通信实现群聊天的功能
1.TCP多线程原理图 2.实现方法 (1)服务器端 (2)客户端 3.java后台代码 主界面 package com.lucky.test50socket2; import android.ann ...
- TCP多线程聊天室
TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...
- C/S模型之TCP群聊
说明:利用TCP协议和多线程实现群聊功能.一个服务器,多个客户端(同一个程序多次启动).客户端向服务端发送数据,由服务端进行转发到其他客户端. /服务端 // WSASever.cpp : 定义控制台 ...
- Java-->实现群聊功能(C/S模式--TCP协议)
--> Java 对TCP协议的支持: --> java.net包中定义了两个类ServerSocket 和Socket ,分别用来实现双向连接的server 端和client 端. -- ...
- [Python 网络编程] TCP编程/群聊服务端 (二)
群聊服务端 需求分析: 1. 群聊服务端需支持启动和停止(清理资源); 2. 可以接收客户端的连接; 接收客户端发来的数据 3. 可以将每条信息分发到所有客户端 1) 先搭架子: #TCP Serve ...
- java基于socket的网络通信,实现一个服务端多个客户端的群聊,传输文件功能,界面使用Swing
最近在复习java的io流及网络编程.但复习写那些样板程序总是乏味的.便准备写个项目来巩固.想来想去还是聊天项目比较好玩.如果日后完成的比较好自己也可以用(哈哈哈).并且自己后面也要继续巩固java多 ...
- 一套高可用、易伸缩、高并发的IM群聊架构方案设计实践
本文原题为“一套高可用群聊消息系统实现”,由作者“于雨氏”授权整理和发布,内容有些许改动,作者博客地址:alexstocks.github.io.应作者要求,如需转载,请联系作者获得授权. 一.引言 ...
随机推荐
- 水 hdu5208 2015-04-20 21:03 36人阅读 评论(0) 收藏
题意: 选择数列中两个数,使得最大公约数最大 分析: 类似筛选法,因为数值不大,可以用b[i]计算i是多少个数的因子.最后取最大的i即可. #include <bits/stdc++.h> ...
- 关于Hive在主节点上与不在主节点上搭建的区别之谈
Hive不在主节点上搭建,我这里是在HadoopSlave1上.
- perl编程问题
一.Hash类型 1.hash遍历输出:如果hash遍历输出的时候不是按key则会按数组输出. my %hash=(); ${hash}{"a"}="1"; $ ...
- mysql 中sql 语句查询今天、昨天、近7天、近30天、一个月内、上一月数据
·1.几个小时内的数据 DATE_SUB(NOW(), INTERVAL 5 HOUR) 1 ·2.今天 select * from 表名 where to_days(时间字段名) = to_days ...
- Web测试要点 做移动端的测试,也做web端的测试,甚至后面桌面端的测试和后台的测试也做了,基本上把我们产品各个端都玩了一轮
Web测试要点 一.功能测试 1.链接测试 (1).测试所有链接是否按指示的那样确实链接到了该链接的页面: (2).测试所链接的页面是否存在: (3).保证Web应用系统上没有孤立的页面(所谓孤立 ...
- 洛谷 P2614 计算器弹琴
P2614 计算器弹琴 题目描述 总所周知,计算器可以拿来干很多它本不应该干的事情,比如写作文.(参看洛谷P2549) 小A发现了一个计算器的另一个隐藏功能——弹琴. http://www.bilib ...
- 【hiho39】二分·归并排序之逆序对
近期申请了微软的暑假实习,4号就要在线笔试了,在线測试系统用的是http://hihocoder.com/,今天试手做了一道题. [题目] 原题链接:http://hihocoder.com/cont ...
- Quartus II sof文件转 jic文件
选择File->Convert Programming Files... Programming File Type选择JTAG Indirect ConfigurationFile(.jic) ...
- 给Linux添加新用户,新建用户,新建帐号
给Linux添加新用户,新建用户,新建帐号 添加用户组 sudo groupadd groupname 添加用户 sudo useradd username -m -s /sbin/nologin - ...
- vue 引入第三方字体包
1.创建 style_css 文件夹,在当前文件夹下 新建 index.css 和 引入字体包. 2. 在build 目录下,设置 webpack.base.cong.js , 在module ...