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. 初学spring boot踩过的坑

    一.搭建spring boot环境 maven工程 pom文件内容 <project xmlns="http://maven.apache.org/POM/4.0.0" xm ...

  2. win7-x64安装mysql5.7.11(官方zip版)

    1.下载官方安装包(http://www.mysql.com/downloads/),此zip包是没有安装器的(*.msi),也没有辅助配置的自动程序. 2.解压zip包,将文件放入指定目录,如:D: ...

  3. JavaWeb 后端 <六> 之 EL & JSTL 学习笔记

    一.EL表达式(特别重要)

  4. Spring3 MVC DispatcherServlet 配置问题

    1. Spring MVC 是通过servlet来进行转发的,一般在web.xml中配置如下: <servlet> <servlet-name>dispatcher</s ...

  5. 自定义程序异常Exception

    /** * 用于循环时的异常定位抛出异常 * 如第i行记录,抛出异常 * @author zhengwei * */ public class MyExcetion extends RuntimeEx ...

  6. Visual Studio自动添加头部注释 -C#开发2010-2013验证

    在团队开发中,头部注释是必不可少的.但在开发每次新建一个类都要复制一个注释模块也很不爽,所以得想个办法让开发工具自动生成我们所需要的模板.....操作方法如下: 找你的vs安装目录, 比如我的是在D盘 ...

  7. java循环、数组练习

    System.out.println("请输入学生个数"); int a=sc.nextInt();//定义一个变量说明学生的数量 int max=0; int[] scores= ...

  8. join和wait

    最近看多线程的时候发现对于join的理解有些错误,在网上查了不少资料,根据自己的理解整理了一下,这里之所以把join和wait放在一起,是因为join的底层实现就是基于wait的,一并讲解更容易理解. ...

  9. java模拟一个抽奖程序

    今天用一个程序模拟一个从1-32之间,随机抽取7组号码的抽奖程序 * 需要使用Java的图形界面知识 * 窗口  JFrame * 面板  JPanel * 显示文本信息的标签  JLabel * 文 ...

  10. TensorFlow conv2d原理及实践

    tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None) 官方 ...