Linux Socket多线程实现简单的多人聊天(pend)
Server:
设置可聊天数为5,为每一个client创建一个线程,这个线程负责接收client的聊天内容并发给其他用户看。
用mutex同步各个线程修改聊天室空余聊天位。
Client:
主线程负责向server发送自己的内容,开一个线程负责接收server发过来别人聊天的内容。
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h> char recv_buf[],send_buf[]; void pthread_function(void* sock_fd){
int sockfd=*(int*)sock_fd;
long recvbytes;
while() {
if((recvbytes=recv(sockfd,recv_buf,,))==-){
printf("recv error");
exit();
}
else{
recv_buf[recvbytes]='\0';
printf("%s\n",recv_buf);
}
}
}
int main(void){
pthread_t id;
int sockfd;
struct sockaddr_in sever_addr; sever_addr.sin_family=AF_INET;
sever_addr.sin_port=htons();
sever_addr.sin_addr.s_addr=inet_addr("10.144.20.79"); if((sockfd=socket(AF_INET,SOCK_STREAM,))==-){
printf("socket error");
exit();
}
if(connect(sockfd,(struct sockaddr*)&sever_addr,sizeof(sever_addr))==-){
printf("connect error");
exit();
}
char name[];
printf("please input your name\n");
scanf("%s",name);
send(sockfd,name,strlen(name),); if(pthread_create(&id,NULL,(void*)pthread_function,(void*)&sockfd)!=)
printf("create thread error\n");
while(){
scanf("%s",send_buf);
fflush(stdin);
if(send(sockfd,send_buf,strlen(send_buf),)==-){
printf("send error");
exit();
}
sleep();
}
close(sockfd);
pthread_cancel(id);
return ;
}
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h> #define COUNT 5
int socket_fd[COUNT]={,-,-,-,-};
pthread_mutex_t emptymutex; int empty=;
/*
the fuction for the thread
*/ void pthread_function(void* clientfd){
char message[];
char buf[];
int i;
long recvbytes;
char name[];
int client_fd=*(int*)clientfd; pthread_mutex_lock(&emptymutex);
if(empty>)
empty--;
else pthread_exit(NULL);
pthread_mutex_unlock(&emptymutex); /*first connect,need to save the name of clients*/
recvbytes=recv(client_fd,name,,);
name[recvbytes]=':';
name[recvbytes+]='\0';
send(client_fd,"welcome to this chatroom,enjoy chatting:",,); while(){
if((recvbytes=recv(client_fd,buf,,))==-){
perror("recv");
pthread_exit(NULL);
}
if(recvbytes==){
printf("%sbye\n",name);
break;
}
buf[recvbytes]='\0';
for (i = ; i < COUNT; ++i)
{
int tmpclient=socket_fd[i];
if(tmpclient!=-){
message[]='\0';
strcat(message,name);
strcat(message,buf);
if(send(tmpclient,message,strlen(message),)==-){
perror("send error");
pthread_exit(NULL);
}
}
}
}
//close socket and reset the fd -1
close(client_fd); pthread_mutex_lock(&emptymutex);
if(empty<)
empty++;
else pthread_exit(NULL);
pthread_mutex_unlock(&emptymutex);
for (i = ; i < COUNT; ++i)
{
if(socket_fd[i]==client_fd)
socket_fd[i]=-;
}
pthread_exit(NULL);
} int main(){
int i;
pthread_mutex_init(&emptymutex,NULL); pthread_t id;
int sockfd,client_fd;
socklen_t sin_size;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-){
perror("socket");
exit();
} my_addr.sin_family=AF_INET;
my_addr.sin_port=htons();
my_addr.sin_addr.s_addr=htonl(INADDR_ANY);
bzero(&(my_addr.sin_zero),); if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-){
perror("bind");
exit();
} if(listen(sockfd,)==-){
perror("listen");
exit();
} i=;
while(){
sin_size=sizeof(struct sockaddr_in);
if((client_fd=accept(sockfd,(struct sockaddr*)&remote_addr,&sin_size))==-){
perror("accept");
exit();
}
if(empty>){
while(socket_fd[i]==-)
i=(i+)%COUNT;
socket_fd[i]=client_fd;
pthread_create(&id,NULL,(void*)pthread_function,(void*)&client_fd);}
else break;
}
pthread_mutex_destroy(&emptymutex);
return ;
}
注意点:
- sockaddr和sockaddr_in的区别
- htonl(INADDR_ANY)设置ip为0.0.0.0,这样会监听所有端口
- server是:socket-bind-listen-accpet-send/recv-close;client是:socket-connect-send/recv-close。
- pthread_create()第三个参数是void*,如果想用int,可以int var=*(int*)client_fd
- bind:address in use是端口已经被打开
- 线程里用pthread_exit(NULL)如果用exit连主线程都会退出
还要改,现在新开一个client可以接受老client的内容,但是老client接收不到新client的内容。还有就是client输入一个什么特定的字符表示结束,以close(socket).
Linux Socket多线程实现简单的多人聊天(pend)的更多相关文章
- Java多线程Socket在控制台输出的多人聊天室编程
服务器端代码 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java ...
- Node + H5 + WebSocket + Koa2 实现简单的多人聊天
服务器代码 ( 依赖于 koa2, koa-websocket ) /* 实例化外部依赖 */ let Koa = require("koa2"); let WebSocket ...
- 66 网络编程(五)——TCP多线程实现多人聊天室
思路 客户端读写各一个类,可以使内部类,实现Runnable.读写类都与服务器端建立连接,一个收,一个发. 客户端实现接收和转发.多线程实现每个客户端的连接(使与各客户端的连接独立). 服务器端中创建 ...
- socket编程,简单多线程服务端测试程序
socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...
- [转]Linux 的多线程编程的高效开发经验
Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别.不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断.本文中我们 ...
- 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥) 介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...
- linux socket高性能服务器处理框架
这个博客很多东西 http://blog.csdn.net/luozhonghua2014/article/details/37041765 思考一种高性能的服务器处理框架 1.首先需要一个内存池 ...
- Linux 的多线程编程的高效开发经验(转)
http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...
- Linux 的多线程编程的高效开发经验
http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...
随机推荐
- jap页面获取struts2中action中变量的值
在jsp页面中可以通过ONGL表达式获取struts2中action处理后的变量的值,这是因为每一个action在初始化后都会放到strackcontext中,可以通过ONGL表达式取到值. 注意要在 ...
- vue.js实现内部自定义指令和全局自定义指令------directive
在Vue中,我们平时数据驱动视图时候,内部自带的指令有时候解决不了一些需求,这时候,Vue给我们一个很好用的东东 directive 这个单词是我们写自定义指令的关键字哦 之定义指令为我们提供了几个钩 ...
- 使用JS开发桌面端应用程序NW.js-2-开发问题小记
前言 本文为开发nw中遇到的各种问题,仅以记录供备忘以及遇到相同问题的人的一点点解决思路. 1. package.json中的window字段无效 原因:package.json中的window字段, ...
- Struts 框架 之 文件上传下载案例
Struts 框架 文件上传 1. 先准备 Struts 环境 (我使用的是struts 2.3.4版本) 导jar包:
- BottomupSort算法 c++代码实现
#include <iostream> using namespace std; #define N 100 int A[N]; static int n; void Initial() ...
- 使用three.js实现机器人手臂的运动效果
Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机.光影.材质等各种对象.你可以在它的主页上看到许多精彩的演示.不过,这款引擎目前还处在比较不成熟的开发阶段 ...
- shiro整合oauth
一.基本思路脑图 二.客户端shiro配置 shiro配置文件 <?xml version="1.0" encoding="UTF-8"?> < ...
- 分享网上搜到的Oracle中对判定条件where 1=1的正解
今天在网上找到了Oracle中对判定条件where 1=1的正解,粘贴出来和大家分享下 1=1 是永恒成立的,意思无条件的,也就是说在SQL语句里有没有这个1=1都可以. 这个1=1常用于应用程序根据 ...
- 读Zepto源码之Callbacks模块
Callbacks 模块并不是必备的模块,其作用是管理回调函数,为 Defferred 模块提供支持,Defferred 模块又为 Ajax 模块的 promise 风格提供支持,接下来很快就会分析到 ...
- DL4NLP——词表示模型(一)表示学习;syntagmatic与paradigmatic两类模型;基于矩阵的LSA和GloVe
本文简述了以下内容: 什么是词表示,什么是表示学习,什么是分布式表示 one-hot representation与distributed representation(分布式表示) 基于distri ...