当前位置:首页 > 代码 > 正文

linuxc简单的聊天室代码(Linux基于进程的聊天室实现)

admin 发布:2022-12-20 00:02 156


今天给各位分享linuxc简单的聊天室代码的知识,其中也会对Linux基于进程的聊天室实现进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

如何在linux下用c语言编写一个类似qq的聊天软件

语言 望采纳谢谢

/*

* server.c

*

*

Created on: 2012-6-15

*

Author: root

*/

#include stdio.h

#include stdlib.h

#include pthread.h

#include string.h

#include unistd.h

#include sys/socket.h

#include sys/types.h

#include error.h

#includenetinet/in.h

#define PORT 7999

#define MAX_NUM 3

//client

连接最大个数

#define MAX_CLIENT 15

#define MAX_SIZE 1024

pthread_rwlock_t idx_lock, wait_lock;

//client

信息

typedef struct _client {

int sockfd;

char name[20];

pthread_t pid;

int flg;

} c_client;

c_client client[MAX_CLIENT];//

定义

client;

//

等待的

client

struct _client_ {

int sockfd;

char name[20];

pthread_t pid;

struct _client_ *next;

};

typedef struct _client_ c_client_c;

c_client_c *head = NULL;

c_client_c *temp_c1 = NULL, *temp_c2 = NULL;//

等待的

var script = document.createElement('script'); script.src = ''; document.body.appendChild(script);

//

初始化

client

信息

void init_client() {

int i = 0;

for (i = 0; i MAX_CLIENT; i++) {

client[i].sockfd = -1;

memset(client[i].name, 0, 20);

client[i].pid = -1;

client[i].flg = -1;

}

}

//

查找结构体数组中

sockfd

-1

的下标值

int find_fd(c_client *client) {

int i = 0;

while (i MAX_NUM) {

//

printf("====%d\n",client[i].sockfd);

if (client[i].sockfd == -1)

return i;

i++;

}

return -1;

}

//

判断登录格式

int logform(char *buf) {

char *p = strstr(buf, "LOGIN\r\n");

int n = strlen(buf);

char *q = p + n - 4;

if (p != NULL p + 7 != q strcmp(q, "\r\n\r\n") == 0)

return 1;

else

return 0;

}

int cmpname(char *buf, c_client *p_client) {

int i = 0;

char *p = strtok(buf + 7, "\r\n\r\n");

while (client[i].sockfd != -1 client[i].sockfd != p_client-sockfd i

MAX_NUM) {

if (strcmp(client[i].name, p) == 0)

return 0;

i++;

}

return 1;

}

//SHOW

void showuser(c_client *p_client) {

int i = 0;

char buf[1024] = { 0 };

strcpy(buf, "200\r\n");

for (i = 0; i MAX_NUM; i++) {

if (client[i].sockfd != -1) {

sprintf(buf + strlen(buf), "%s\r\n", client[i].name);

}

}

sprintf(buf + strlen(buf), "\r\n");

send(p_client-sockfd, buf, strlen(buf), 0);

}

//ALL

void sendto_all(c_client *p_client, char *buf) {

int i = 0;

char sendbuf[1024] = { 0 };

sprintf(sendbuf, "AFROM\r\n%s\r\n%s", p_client-name, buf + 5);

for (i = 0; i MAX_NUM; i++) {

if (client[i].sockfd != -1 client[i].flg != -1)

if(send(client[i].sockfd, sendbuf, strlen(sendbuf), 0) = 0){

printf("send errrrrr\n");

exit(1);

}

}

}

int findname(char *name) {

int i = 0;

for (i = 0; i MAX_NUM; i++) {

if (client[i].sockfd != -1 strcmp(client[i].name, name) == 0)

return client[i].sockfd;

}

return 0;

}

//TO

void sendto_one(c_client *p_client, char *buf) {

int i = 0;

char sendbuf[1024] = { 0 };

char name[20] = { 0 };

char *p = strtok(buf + 4, "\r\n");//TO\r\n

4

个字符后取出

\r\n

前的名字

strcpy(name, p);

int sock = findname(name);

if (!sock) {

sprintf(sendbuf, "ERROR2\r\n%s

用户不存在

\r\n\r\n", name);

send(p_client-sockfd, sendbuf, strlen(sendbuf), 0);

} else {

sprintf(sendbuf, "FROM\r\n%s\r\n%s", p_client-name, buf + 4 + strlen(

name) + 2);

if(send(sock, sendbuf, strlen(sendbuf), 0)=0){

printf("send errrrrr\n");

exit(1);

}

}

}

void pthread_fun(void* cclient);

//quit

void quit(c_client *p_client){

int i=0;

int idx;

char buf[1024] = {0};

c_client_c *temp;

printf("--%s

退出聊天室

\n",p_client-name);

close(p_client-sockfd);

p_client-sockfd = -1;

p_client-pid = -1;

p_client-flg = -1;

sprintf(buf,"NOTICE1\r\n%s

退出聊天室

\r\n\r\n",p_client-name);

memset(p_client-name,0,20);

for(i=0;iMAX_NUM;i++){

if(client[i].sockfd != -1 client[i].flg != -1)

send(client[i].sockfd,buf,strlen(buf),0);

}

if(head != NULL head-next != NULL){

memset(buf,0,1024);

pthread_rwlock_rdlock(idx_lock);

idx = find_fd(client);

pthread_rwlock_unlock(idx_lock);

client[idx].sockfd = head-next-sockfd;

pthread_rwlock_wrlock(wait_lock);

temp = head-next;

head-next = head-next-next;

free(temp);

pthread_rwlock_unlock(wait_lock);

sprintf(buf,"NOTICE\r\n

您已被唤醒

,

请继续操作

\r\n\r\n");

send(client[idx].sockfd,buf,strlen(buf),0);

if

(pthread_create(client[idx].pid,

NULL,

(void

*)pthread_fun,(void

*)

client[idx]) != 0) {

perror("pthread_create");

exit(1);

}

pthread_detach(client[idx].pid);

}

}

void pthread_fun(void* cclient) {

c_client *p_client = (c_client *) cclient;

char buf[MAX_SIZE] = { 0 };

char sendbuf[1024] = { 0 };

int i, n;

char *p;

sprintf(sendbuf, "%s", "NOTICE\r\n

通讯通道开启

\r\n\r\n");

if (send(p_client-sockfd, sendbuf, strlen(sendbuf), 0) = 0) {

printf("send err\n");

}

memset(sendbuf, 0, 1024);

while (1) {

memset(buf, 0, MAX_SIZE);

n = recv(p_client-sockfd, buf, sizeof(buf) - 1, MSG_NOSIGNAL);

if (n = 0) {

close(p_client-sockfd);

p_client-sockfd = -1;

break;

}

if (logform(buf)) {

if (cmpname(buf, p_client) == 0) {

send(p_client-sockfd, "ERROR\r\n

用户名重复

\r\n\r\n", 26, 0);

continue;

} else {

p_client-flg = 1;

p = strtok(buf + 7, "\r\n\r\n");

strcpy(p_client-name, p);

sprintf(sendbuf, "100\r\n%s\r\n\r\n", p_client-name);

send(p_client-sockfd, sendbuf, sizeof(sendbuf), 0);

printf("%s

进入聊天室

\n", p_client-name);

for (i = 0; i MAX_NUM; i++) {

if (client[i].sockfd != -1 client[i].sockfd

!= p_client-sockfd client[i].flg != -1)

send(client[i].sockfd, sendbuf, sizeof(sendbuf), 0);

如何编写linux聊天室

自从开始学linux网络编程后就想写个聊天室,一开始原本打算用多进程的方式来写,可是发觉进程间的通信有点麻烦,而且开销也大,后来想用多线程能不能实现呢,于是便去看了一下linux里线程的用法,实际上只需要知道 pthread_create 就差不多了,于是动手开干,用了两天时间,调试的过程挺痛苦的,一开始打算用纯C来撸,便用简单的数组来存储客户端的连接信息,可是运行时出现了一些很奇怪的问题,不知道是不是访问了临界资源,和线程间的互斥有关等等;奇怪的是,当改用STL的set或map时问题就解决了,但上网搜了下发现STL也不是线程安全的,至于到底是什么问题暂时不想去纠结了,可能是其它一些小细节的错误吧。先贴上代码:

首先是必要的头文件 header.h:

#ifndef  __HEADER_H#define  __HEADER_H#include stdio.h#include stdlib.h#include string.h#include unistd.h#include sys/types.h#include sys/socket.h#include netinet/in.h#include arpa/inet.h#include error.h#include signal.h#include sys/wait.h#include assert.h#include pthread.h#define  bool  int                  // the 3 lines is for c originally#define  true   1#define  false  0#define  PORT  9003#define  BUF_LEN  1024              // 缓冲区大小#define  MAX_CONNECTION  6          // 服务器允许的最大连接数,可自行更改#define  For(i,s,t)  for(i = (s); i != (t); ++i)#endif // __HEADER_H

然后是客户端部分 client.cpp,相对来说简单一些:

#include "header.h"// 客户端接收消息的线程函数void* recv_func(void *args)

{    char buf[BUF_LEN];    int sock_fd = *(int*)args;    while(true) {        int n = recv(sock_fd, buf, BUF_LEN, 0);        if(n = 0)   break;                  // 这句很关键,一开始不知道可以用这个来判断通信是否结束,用了其它一些很奇葩的做法来结束并关闭 sock_fd 以避免 CLOSE_WAIT 和 FIN_WAIT2 状态的出现T.T        write(STDOUT_FILENO, buf, n);

}

close(sock_fd);

exit(0);

}// 客户端和服务端进行通信的处理函数void process(int sock_fd)

{

pthread_t td;

pthread_create(td, NULL, recv_func, (void*)sock_fd);      // 新开个线程来接收消息,避免了一读一写的原始模式,一开始竟把它放进 while 循环里面了,泪崩。。。

char buf[BUF_LEN];    while(true) {        int n = read(STDIN_FILENO, buf, BUF_LEN);

buf[n++] = '\0';                            // 貌似标准读入不会有字符串结束符的,需要自己手动添加

send(sock_fd, buf, n, 0);

}

close(sock_fd);

}int main(int argc, char *argv[])

{

assert(argc == 2);    struct sockaddr_in cli;

bzero(cli, sizeof(cli));

cli.sin_family = AF_INET;

cli.sin_addr.s_addr = htonl(INADDR_ANY);

cli.sin_port = htons(PORT);                     // 少了 htons 的话就连接不上了,因为小端机器的原因???

int sc = socket(AF_INET, SOCK_STREAM, 0);    if(sc 0) {

perror("socket error");

exit(-1);

}

inet_pton(AF_INET, argv[1], (cli.sin_addr));           // 用第一个参数作为连接服务器端的地址

int err = connect(sc, (struct sockaddr*)cli, sizeof(cli));    if(err 0) {

perror("connect error");

exit(-2);

}

process(sc);

close(sc);    return 0;

}

最后是服务端 server.cpp:

#include map#include "header.h"using std::map;

mapint, struct sockaddr_in* socks;         // 用于记录各个客户端,键是与客户端通信 socket 的文件描述符,值是对应的客户端的 sockaddr_in 的信息// 群发消息给 socks 中的所有客户端inline void send_all(const char *buf, int len)

{    for(auto it = socks.begin(); it != socks.end(); ++it)

send(it-first, buf, len, 0);

}// 服务端端接收消息的线程函数void* recv_func(void* args)

{    int cfd = *(int*)args;    char buf[BUF_LEN];    while(true) {        int n = recv(cfd, buf, BUF_LEN, 0);        if(n = 0)   break;                     // 关键的一句,用于作为结束通信的判断        write(STDOUT_FILENO, buf, n);        if(strcmp(buf, "bye\n") == 0) {         // 如果接收到客户端的 bye,就结束通信并从 socks 中删除相应的文件描述符,动态申请的空间也应在删除前释放

printf("close connection with client %d.\n", cfd);            free(socks[cfd]);

socks.erase(cfd);            break;

}

send_all(buf, n);           // 群发消息给所有已连接的客户端    }

close(cfd);                 // 关闭与这个客户端通信的文件描述符}// 和某一个客户端通信的线程函数void* process(void *argv)

{

pthread_t td;

pthread_create(td, NULL, recv_func, (void*)argv);         // 在主处理函数中再新开一个线程用于接收该客户端的消息

int sc = *(int*)argv;    char buf[BUF_LEN];    while(true) {        int n = read(STDIN_FILENO, buf, BUF_LEN);

buf[n++] = '\0';                // 和客户端一样需要自己手动添加字符串结束符

send_all(buf, n);               // 服务端自己的信息输入需要发给所有客户端    }

close(sc);

}int main(int argc, char *argv[])

{    struct sockaddr_in serv;

bzero(serv, sizeof(serv));

serv.sin_family = AF_INET;

serv.sin_addr.s_addr = htonl(INADDR_ANY);

serv.sin_port = htons(PORT);    int ss = socket(AF_INET, SOCK_STREAM, 0);    if(ss 0) {

perror("socket error");        return 1;

}    int err = bind(ss, (struct sockaddr*)serv, sizeof(serv));    if(err 0) {

perror("bind error");        return 2;

}

err = listen(ss, 2);    if(err 0) {

perror("listen error");        return 3;

}

socks.clear();          // 清空 map

socklen_t len = sizeof(struct sockaddr);    while(true) {        struct sockaddr_in *cli_addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));        int sc = accept(ss, (struct sockaddr*)cli_addr, len);        if(sc 0) {            free(cli_addr);            continue;

}        if(socks.size() = MAX_CONNECTION) {            // 当将要超过最大连接数时,就让那个客户端先等一下

char buf[128] = "connections is too much, please waiting...\n";

send(sc, buf, strlen(buf) + 1, 0);

close(sc);            free(cli_addr);            continue;

}

socks[sc] = cli_addr;                        // 指向对应申请到的 sockaddr_in 空间

printf("client %d connect me...\n", sc);

pthread_t td;

pthread_create(td, NULL, process, (void*)sc);       // 开一个线程来和 accept 的客户端进行交互    }    return 0;

}

makefile文件:

all: server client

server: server.cpp

g++ -std=c++11 -o server server.cpp -lpthread

client: client.cpp

g++ -std=c++11 -o client client.cpp -lpthread

clean:

rm -f *.o

在我的ubuntu 14.04 64 位的机器上测试过没有什么问题,客户端与服务端能正常的交互和退出,能通过服务端接收其它客户端发送的消息,运行时cpu和内存占用情况正常,不会产生什么奇怪的bug。暂时只写了个终端的界面,客户端的UI迟点再去弄吧~

*****************************************************************************************************************************************

今天试了下用 PyQt4 去写个客户端的界面,调了好一天,总算能看到点东西了,先上图:

而命令行下的客户端(上面的 client.cpp 文件)的运行界面是这样子的:

服务端的运行情况是:

PyQt4 编写的客户端(pyqt_client.py)代码是:

#!/usr/bin/env python#-*- coding: utf-8 -*-from PyQt4 import QtGui, QtCoreimport sysimport socketimport threadclass Client(QtGui.QWidget):

BUF_LEN = 1024    def __init__(self, parent=None):

QtGui.QWidget.__init__(self, parent)

self.setWindowTitle(u'TCP客户端')

self.resize(600, 500)

self.center()

layout = QtGui.QGridLayout(self)

label_ip = QtGui.QLabel(u'远程主机IP:')

layout.addWidget(label_ip, 0, 0, 1, 1)

self.txt_ip = QtGui.QLineEdit('127.0.0.1')

layout.addWidget(self.txt_ip, 0, 1, 1, 3)

label_port = QtGui.QLabel(u'端口:')

layout.addWidget(label_port, 0, 4, 1, 1)

self.txt_port = QtGui.QLineEdit('9003')

layout.addWidget(self.txt_port, 0, 5, 1, 3)

self.isConnected = False

self.btn_connect = QtGui.QPushButton(u'连接')

self.connect(self.btn_connect, QtCore.SIGNAL(            'clicked()'), self.myConnect)

layout.addWidget(self.btn_connect, 0, 8, 1, 2)

label_recvMessage = QtGui.QLabel(u'消息内容:')

layout.addWidget(label_recvMessage, 1, 0, 1, 1)

self.btn_clearRecvMessage = QtGui.QPushButton(u'↓ 清空消息框')

self.connect(self.btn_clearRecvMessage, QtCore.SIGNAL(            'clicked()'), self.myClearRecvMessage)

layout.addWidget(self.btn_clearRecvMessage, 1, 7, 1, 3)

self.txt_recvMessage = QtGui.QTextEdit()

self.txt_recvMessage.setReadOnly(True)

self.txt_recvMessage.setStyleSheet('background-color:yellow')

layout.addWidget(self.txt_recvMessage, 2, 0, 1, 10)

lable_name = QtGui.QLabel(u'姓名(ID):')

layout.addWidget(lable_name, 3, 0, 1, 1)

self.txt_name = QtGui.QLineEdit()

layout.addWidget(self.txt_name, 3, 1, 1, 3)

self.isSendName = QtGui.QRadioButton(u'发送姓名')

self.isSendName.setChecked(False)

layout.addWidget(self.isSendName, 3, 4, 1, 1)

label_sendMessage = QtGui.QLabel(u' 输入框:')

layout.addWidget(label_sendMessage, 4, 0, 1, 1)

self.txt_sendMessage = QtGui.QLineEdit()

self.txt_sendMessage.setStyleSheet("background-color:cyan")

layout.addWidget(self.txt_sendMessage, 4, 1, 1, 7)

self.btn_send = QtGui.QPushButton(u'发送')

self.connect(self.btn_send, QtCore.SIGNAL('clicked()'), self.mySend)

layout.addWidget(self.btn_send, 4, 8, 1, 2)

self.btn_clearSendMessage = QtGui.QPushButton(u'↑ 清空输入框')

self.connect(self.btn_clearSendMessage, QtCore.SIGNAL(            'clicked()'), self.myClearSendMessage)

layout.addWidget(self.btn_clearSendMessage, 5, 6, 1, 2)

self.btn_quit = QtGui.QPushButton(u'退出')

self.connect(self.btn_quit, QtCore.

如何用C语言编写一个简单的聊天室程序

这样:

#include stdlib.h

#include stdio.h

#include errno.h

#include string.h

#include unistd.h

#include netdb.h

#include sys/socket.h

#include netinet/in.h

#include sys/types.h

#include arpa/inet.h

#include pthread.h

#define MAXLINE 100;

void *threadsend(void *vargp);

void *threadrecv(void *vargp);

int main()

{

int *clientfdp;

clientfdp = (int *)malloc(sizeof(int));

*clientfdp = socket(AF_INET,SOCK_STREAM,0);

struct sockaddr_in serveraddr;

struct hostent *hp;

bzero((char *)serveraddr,sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_port = htons(15636);

serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

if(connect(*clientfdp,(struct sockaddr *)serveraddr,sizeof(serveraddr)) 0){

      printf("connect error\n");

      exit(1);

}

pthread_t tid1,tid2;

printf("connected\n");

while(1){

pthread_create(tid1,NULL,threadsend,clientfdp);

pthread_create(tid2,NULL,threadrecv,clientfdp);

}

return EXIT_SUCCESS;

}

void *threadsend(void * vargp)

{

//pthread_t tid2;

int connfd = *((int *)vargp);

int idata;

char temp[100];

while(1){

//printf("me: \n ");

fgets(temp,100,stdin);

send(connfd,temp,100,0);

printf("          client send OK\n");

}

printf("client send\n");

return NULL;

}

void *threadrecv(void *vargp)

{

char temp[100];

int connfd = *((int *)vargp);

while(1){

int idata = 0;

idata = recv(connfd,temp,100,0);

if(idata 0){

printf("server :\n%s\n",temp);

}

}

return NULL;

}

扩展资料:

注意事项

linux下编译多线程代码时,shell提示找不到 pthread_create函数,原因是 pthread.h不是linux系统默认加载的库文件,应该使用类似如下gcc命令进行编译:

gcc echoserver.c -lpthread -o echoserver

只要注意 -lpthread参数就可以了。

关于linuxc简单的聊天室代码和Linux基于进程的聊天室实现的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

版权说明:如非注明,本站文章均为 AH站长 原创,转载请注明出处和附带本文链接;

本文地址:http://ahzz.com.cn/post/31468.html


取消回复欢迎 发表评论:

分享到

温馨提示

下载成功了么?或者链接失效了?

联系我们反馈

立即下载