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)的更多相关文章

  1. Java多线程Socket在控制台输出的多人聊天室编程

    服务器端代码 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java ...

  2. Node + H5 + WebSocket + Koa2 实现简单的多人聊天

    服务器代码  ( 依赖于 koa2,  koa-websocket ) /* 实例化外部依赖 */ let Koa = require("koa2"); let WebSocket ...

  3. 66 网络编程(五)——TCP多线程实现多人聊天室

    思路 客户端读写各一个类,可以使内部类,实现Runnable.读写类都与服务器端建立连接,一个收,一个发. 客户端实现接收和转发.多线程实现每个客户端的连接(使与各客户端的连接独立). 服务器端中创建 ...

  4. socket编程,简单多线程服务端测试程序

    socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...

  5. [转]Linux 的多线程编程的高效开发经验

    Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别.不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断.本文中我们 ...

  6. 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)   介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...

  7. linux socket高性能服务器处理框架

    这个博客很多东西 http://blog.csdn.net/luozhonghua2014/article/details/37041765   思考一种高性能的服务器处理框架 1.首先需要一个内存池 ...

  8. Linux 的多线程编程的高效开发经验(转)

    http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...

  9. Linux 的多线程编程的高效开发经验

    http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 背景 Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多 ...

随机推荐

  1. 逆波兰表达式的C实现

    复习下数据结构,用栈简单实现逆波兰表达式,参考文档: http://www.nowamagic.net/librarys/veda/detail/2307 http://www.nowamagic.n ...

  2. Java异常体系简析

    最近在阅读<Java编程思想>的时候看到了书中对异常的描述,结合自己阅读源码经历,谈谈自己对异常的理解.首先记住下面两句话: 除非你能解决这个异常,否则不要捕获它,如果打算记录错误消息,那 ...

  3. CSS学习笔记一:css 画平面图形

    最近在学习CSS,先从CSS画点平面图形入手,发现除了正方形.长方形此类比较简单,只要有长宽设置恰当即可,画圆要涉及radius,然后恢复到做界面的最讨厌的状态了,不断的修改设值,调整数据,所幸并不多 ...

  4. 使用Publish Over SSH插件实现远程自动部署

    背景: 现场的部署环境开放外网环境困难,只有一台机器能够开发外网,应对该情况,所有的补丁文件需要直接在master机器上面生成,然后命令移动到其他的服务器上面去. 这里使用到了jenkins的Publ ...

  5. springmvc精讲

    转自http://www.cnblogs.com/baiduligang/p/4247164.html

  6. ARM开发(3)基于STM32的矩阵键盘控制蜂鸣器

    一 矩阵键盘控制蜂鸣器原理:  1.1 本实验实现8*7矩阵键盘上按键控制蜂鸣器响.  1.2 实验思路:根据电路图原理,找出矩阵键盘行列所对应的引脚,赋予对应的按键值,然后控制蜂鸣器响.  1.3 ...

  7. 修改User-Agent来伪装浏览器访问手机站点

    有时候为了测试需要,可能需要使用测试手机wap这样的站点,如果用真正的手机去测试也可以实现,但是比较麻烦,我们可以通过设置chrome的user agent来伪装浏览器,达到我们的测试目的. 代码如下 ...

  8. yum 源问题

    YUM源搭建 1.yum源是yum安装的获取源地,yum  = 红帽包管理 echo /dve/sr0 /media ios9660 defaults 0 0 >> /etc/fstab ...

  9. css3关键帧动画实现轮播效果

    实现效果:打开手机京东,可以看到首页的头部,以这个头部为基础,仿写一个类似的样式. 思路:仔细观察可以发现,手机京东的头部是以一个搜索栏和轮播特效组成的,而这个搜索栏是以轮播特效做为背景的,现在运用c ...

  10. UESTC 30 &&HDU 2544最短路【Floyd求解裸题】

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...