Linux Socket编程---TCP实现多客户端的网络聊天室
程序员文章站
2022-03-15 20:34:47
...
本程序实现的功能:
基于linux的网络聊天室
服务器端功能:
1)能够实现同时监听10个客户端
2)新的客户进入聊天室,发送新客户进入的系统消息给所有在线客户
3)在线客户实现基本的群聊功能
4)保存聊天记录,并支持查询聊天记录
5)可以通过终端查看客户之间的聊天状况
客户端功能:
1)能过正常连接服务器
2)通过多线程实现同时进行收发消息
3)保存客户本地聊天记录
4)可以查询本地聊天记录
tcpserver.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
//给线程传输的信息
struct threadinfo
{
//socket
int my_sock;
//随机分配的端口号
int my_port;
};
//用户数量
int usernum = 0;
//socket数组
int sock_array[10];
//打开文件
int fd;
//发送线程
void *recvsocket(void *arg)
{
//接受结构体
struct threadinfo *thread = arg;
int st = thread->my_sock;
int port = thread->my_port;
char receivebuffer[100];
int i;
int n;
int length = sizeof(sock_array)/sizeof(sock_array[0]);
char sendbuffer[100];
char writebuffer[100];
while(1){
//接受客户端传回的数据
memset(receivebuffer, 0, sizeof(receivebuffer));
n = recv(st, receivebuffer, sizeof(receivebuffer), 0);
//判断通信是否结束
if(n <= 0)
break;
printf("来自%d的数据:%s\n", port,receivebuffer);
//将接受到的聊天记录保存到文件中
memset(writebuffer, 0, sizeof(writebuffer));
sprintf(writebuffer,"%d",port);
strcat(writebuffer,":");
strcat(writebuffer,receivebuffer);
strcat(writebuffer,"\n");
write(fd,writebuffer,sizeof(writebuffer));
//将接受到的消息发送给出自己外的其他人
memset(sendbuffer, 0, sizeof(sendbuffer));
sprintf(sendbuffer,"%d",port);
strcat(sendbuffer,"说:");
strcat(sendbuffer,receivebuffer);
for(i = 0; i<length; i++)
{
if(sock_array[i] != st)
{
send(sock_array[i], sendbuffer, strlen(sendbuffer), 0);
}
}
}
return NULL;
}
int main() {
//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, 0);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));//每个字节都用0填充
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(6666);
//服务器绑定信息
if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("bind failed!");
exit(1);
}
//进入监听状态,等待用户发起请求
printf("监听6666端口...\n");
//创建新的sockaddr_in结构体用于accept
struct sockaddr_in client_addr;
//声明线程数组
pthread_t thrd[10];
int client_sock;
int len = sizeof(client_addr);
//声明一个结构体,放入下面的数组中
struct threadinfo my_thread;
//声明一个结构体数组
struct threadinfo thread_array[10];
int i;
char portbuffer[100];
//开始监听,监听10个用户
listen(serv_sock, 10);
//pthread_create(&thrd[11], NULL, sendsocket, &sock_array);
//打开文件
fd = open("./note.txt", O_CREAT|O_WRONLY|O_APPEND);
while(1)
{
//printf("123");
//accept()接收返回值为客户端的新socket,原来的socket用户继续监听端口
client_sock = accept(serv_sock, (struct sockaddr*)&client_addr, &len);
if(client_sock < 0) {
perror("connect failed!");
exit(1);
}
printf("欢迎%d用户进入聊天室!\n", client_addr.sin_port);
//向所有用户发送进入信息
memset(portbuffer, 0, sizeof(portbuffer));
sprintf(portbuffer,"%d",client_addr.sin_port);
strcat(portbuffer,"用户进入聊天室!");
for(i = 0; i<usernum; i++)
{
send(sock_array[i], portbuffer, strlen(portbuffer), 0);
}
//username[usernum] = client_addr.sin_port;
//将socket和port放入结构体中 再将这个结构体放入的结构体数组中
my_thread.my_sock = client_sock;
my_thread.my_port = client_addr.sin_port;
thread_array[usernum] = my_thread;
//socket数组
sock_array[usernum] = client_sock;
//创建发送线程
pthread_create(&thrd[usernum], NULL, recvsocket, &thread_array[usernum]);
//用户数量自增
usernum++;
}
//关闭文件
close(fd);
//关闭套接字
close(client_sock);
close(serv_sock);
return 0;
}
tcpclient.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
//打开文件
int fd;
//客户端socket
int client_sock;
//文件路径
char path[100];
//段口号
char port[100];
//发送线程
void *sendsocket(void *arg)
{
//接受socket
int st = *(int *)arg;
char sendbuffer[100];
char writebuffer[100];
while(1){
//向服务器发送数据
memset(sendbuffer, 0, sizeof(sendbuffer));
//printf("请输入消息:");
scanf("%s",sendbuffer);
memset(writebuffer, 0, sizeof(writebuffer));
strcat(writebuffer,sendbuffer);
strcat(writebuffer,"\n");
//写入文件
write(fd,writebuffer,sizeof(writebuffer));
//发送消息
send(st, sendbuffer, strlen(sendbuffer), 0);
}
return NULL;
}
//接受线程
void *recvsocket(void *arg)
{
int st = *(int *)arg;
char receivebuffer[100];
char writebuffer[100];
int n;
while(1){
//读取服务器传回的数据
memset(receivebuffer, 0, sizeof(receivebuffer));
n = recv(st, receivebuffer, sizeof(receivebuffer), 0);
//用于判断通信是否结束
if(n<=0)
break;
memset(writebuffer, 0, sizeof(writebuffer));
strcat(writebuffer,receivebuffer);
strcat(writebuffer,"\n");
//写入文件
write(fd,writebuffer,sizeof(writebuffer));
//输出
printf("%s\n", receivebuffer);
}
return NULL;
}
int main() {
//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));//每个字节都用0填充
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(6666);
//连接服务器,成功返回0
client_sock = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if(client_sock == 0) {
printf("服务器连接成功!\n");
}
//新建一个结构体
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
int len = sizeof(client_addr);
//获得本程序的sockaddr_in结构体
int ti = getsockname(sock, (struct sockaddr*)&client_addr, &len);
//对字符串拼接得到路径
sprintf(port,"%d",client_addr.sin_port);
strcat(path,"./usernote/");
strcat(path,port);
//打开文件
fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_APPEND|O_NONBLOCK);
if(fd == -1)
{
printf("失败!");
}
//创建发送接受两个线程 一个接受线程一个发送线程
pthread_t thrd1, thrd2;
pthread_create(&thrd1, NULL, sendsocket, &sock);
pthread_create(&thrd2, NULL, recvsocket, &sock);
pthread_join(thrd1, NULL);
pthread_join(thrd2, NULL);
//关闭文件
close(fd);
//关闭套接字
close(sock);
return 0;
}
推荐阅读
-
Java编程实现基于TCP协议的Socket聊天室示例
-
基于Java的Socket类Tcp网络编程实现实时聊天互动程序:QQ聊天界面的搭建
-
linux 网络编程 socket选项的实现
-
linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
-
socket套接字、基于TCP的编程模型与实际运用(网络聊天室)
-
LINUX下的Socket网络编程TCP/IP
-
基于Java的Socket类Tcp网络编程实现实时聊天互动程序(三):回车实现数据到发送(详细代码完结)
-
基于Java的Socket类Tcp网络编程实现实时聊天互动程序(二):Tcp通信的过程及代码编写
-
【Socket网络通信】利用TCP/IP协议实现从服务端的文件中读取数据打印到客户端的控制台,服务端对客户端输入过来的数据做出响应...
-
基于TCP协议的socket编程实现简单聊天室——客户端多线程