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. Sublime Text 3 注册码

    最近觉得Sublime Text3比Notepad++好使,可惜需要购买,于是网上搜了一下,屌丝的福音啊: Sublime Text Build 3065 License key复制如下三个任意一个正 ...

  2. IE过滤器

    1.  _ 下划线属性过滤器  语法:_选择符{属性:属性值}   2. *通配符属性过滤器 语法:*选择符{属性:属性值}   3.  \9: IE版本识别:其他浏览器都不识别 语法:选择符{属性: ...

  3. JAVA - 深入JAVA 虚拟机 1

    Java虚拟机与程序的生命周期 Java虚拟机将结束生命周期 1.call System.exit(n) Terminates the currently running JVM. 2.程序正常执行结 ...

  4. 面向对象15.3String类-常见功能-转换

    public static void main(String[] args) { //2.1// String s="张三,李四,王五";// String [] arr=s.sp ...

  5. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  6. Javascript百学不厌-递归

    虽然偶尔也用过,但是从来没具体来整理过 普通递归: function fac(n) { ) ; ); } fac() 这是个阶乘.但是占用内存,因为: fac(5) (5*fac(4)) (5*(4* ...

  7. 【一步一步】Spring 源码环境搭建

    平时项目中基本上都会用到spring,但是源码还没有深入的了解过.趁这段时间稍微空闲点,开始研究下spring 源码.下面是spring 源码的环境搭建. 主要分为如下步骤: ①安装jdk,gradl ...

  8. [luogu]P1379 八数码难题[广度优先搜索]

    八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...

  9. (转)Java里的堆(heap)栈(stack)和方法区(method)(精华帖,多读读)

    [color=red][/color]<一> 基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈 ...

  10. [javascript] visible - 待写

    摘要 jquery 有个筛选器 visible , 一般用于选择 可见元素 $('p:visible') 就是选择可见的 p 元素. 但发现有时候不可用.!!