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. vue.js+UEditor集成 [前后端分离项目]

    首先,谈下这篇文章中的前后端所涉及到的技术框架内容. 虽然是后端的管理项目,但整体项目,是采用前后端分离的方式完成,这样做的目的也是产品化的需求: 前端,vue+vuex+vue router+web ...

  2. 剥析surging的架构思想

    1.前言   前面第一篇阐述了采用基于.NET CORE微服务架构,应用surging服务端与客户端之间进行通信的简单示例以及对于surging服务化框架简单介绍.在这篇文章中,我们将剥析surgin ...

  3. Android项目导入工程Module

    在Android开发过程中,我们经常引用一些模块,或者自己封装好的Project.在Android Studio某个项目是可以引入多个Module的.这样导入Module的好处方便对源码修改以适合自己 ...

  4. 流畅python学习笔记:第十一章:抽象基类

    __getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...

  5. HTLM5新增属性

    1.<meta http-equiv="Pragma" content="no-cache"/> //禁止页面缓存 2.<script def ...

  6. 【转载】Android 开发 命名规范

    原文地址:http://www.cnblogs.com/ycxyyzw/p/4103284.html 标识符命名法标识符命名法最要有四种: 1 驼峰(Camel)命名法:又称小驼峰命名法,除首单词外, ...

  7. Java多线程缓存器简单实现

    package com.charles.utils; import java.util.HashMap; import java.util.Map; import java.util.concurre ...

  8. Spring mybatis源码篇章-sql mapper配置文件绑定mapper class类

    前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 背景知识 MappedStatement是mybatis操作sql ...

  9. 【流量】netflow 基础知识

    摘要 记录下关于netflow的基础知识以及应用,现状 是什么 一种数据交换方式,NetFlow流量统计数据包括数据流时戳 源IP地址和目的IP地址 源端口号和目的端口号 输入接口号和输出接口号 下一 ...

  10. Asp.Net MVC-4-过滤器1:认证与授权

    基础 过滤器体现了MVC框架中的Aop思想,虽然这种实现并不完美但在实际的开发过程中一般也足以满足需求了. 过滤器分类 依据上篇分析的执行时机的不同可以把过滤器按照实现不同的接口分为下面五类: IAu ...