废话不多说直接上干货
1.目标
在实现回声服务器和客户端后 ,基于多线程设计一对一的聊天室
2.功能
在本机上实现客户端与服务器的实时聊天测试 以达到练习强化socket通信/多线程技术的目的
3.测试
客户端主线程 与两个子线程
服务器主线程 与两个子线程
能够相互收到信息 并且进行应答
最后关闭socket
代码如下:
客户端:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>
#define BUF_SIZE 1024
#define SERVER_PORT 666
#define SERVER_IP "127.0.0.1"
char buf_send[BUF_SIZE]={0};
char buf_recv[BUF_SIZE]={0};
//发送线程功能函数
void * sendMsg(void * socket){
int *client_sock = (int *)socket;
while(1){
scanf("%s",buf_send);//buf_send表示数组元素首地址 此时再往里边输入数据 会覆盖掉原数据
send(*client_sock, buf_send, strlen(buf_send), 0);//因为第一个形参传过来的是个地址所以加*号才是int
//退出发送
if(!strncasecmp(buf_send, "quit", 4)){
//该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
break;
}
}
pthread_exit(NULL);
}
//接受线程功能函数
void * recvMsg(void * socket){
int *client_sock = (int *)socket;
while(1){
bzero(buf_recv, BUF_SIZE);//先把buf清零
if(recv(*client_sock, buf_recv, BUF_SIZE, 0)>0){
printf("Msg from server: %s\n", buf_recv);
}
if(!strncasecmp(buf_send, "quit", 4)){
//该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
break;
}
}
pthread_exit(NULL);
}
//客户端首先创建一个socket
//绑定想要连接的服务器的IP和端口号 然后调用connect函数通过socket去连接服务器
int main()
{
int sockfd;
struct sockaddr_in servaddr;
int n;
sockfd=socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, '\0', sizeof(struct sockaddr_in));
//此处需要标明服务器的IP和端口
servaddr.sin_family=AF_INET;
//将IP和端口号进行转化 转化为网络字节序 就是socket函数使用的IP和端口格式
inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
servaddr.sin_port = htons(SERVER_PORT);
if((connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))>=0){
printf("连接成功!\n");
}
if((recv(sockfd, buf_recv, BUF_SIZE, 0))>0){
printf("message from server: %s\n", buf_recv);
}
//创建线程用于收发
pthread_t send_tid, recv_tid;
pthread_create(&send_tid, NULL, sendMsg, (void *)&sockfd);
pthread_create(&recv_tid, NULL, recvMsg, (void *)&sockfd);
//此函数表示 子线程 结束 才能执行 主线程中后边的函数(防止子线程被中断)
pthread_join(send_tid, NULL);
pthread_join(recv_tid, NULL);
close(sockfd);
return 0;
}
服务器:
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define SERVER_PORT 666
#define BUF_SIZE 1024
char buf_send[BUF_SIZE] = "connection succeeded";
char buf_recv[BUF_SIZE];
//发送线程功能函数
void * sendMsg(void * socket){
int *client_sock = (int *)socket;
while(1){
scanf("%s",buf_send);//buf_send表示数组元素首地址 此时再往里边输入数据 会覆盖掉原数据
send(*client_sock, buf_send, strlen(buf_send), 0);//因为第一个形参传过来的是个地址所以加*号才是int
//退出发送
if(!strncasecmp(buf_send, "quit", 4)){
//该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
break;
}
}
pthread_exit(NULL);
}
//接受线程功能函数
void * recvMsg(void * socket){
int *client_sock = (int *)socket;
while(1){
bzero(buf_recv, BUF_SIZE);//先把buf清零
if(recv(*client_sock, buf_recv, BUF_SIZE, 0)>0){
printf("Msg from client: %s\n", buf_recv);
}
if(!strncasecmp(buf_send, "quit", 4)){
//该函数就是对比第一个字符串和第二个字符串 的前4个字符是否相等 相等返回零
break;
}
}
pthread_exit(NULL);
}
int main()
{
int sock;//信箱
int i;
struct sockaddr_in server_addr;
sock = socket(AF_INET, SOCK_STREAM, 0);//创建信箱
bzero(&server_addr,sizeof(server_addr));//清空标签
server_addr.sin_family=AF_INET;//选择协议族
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//监听本地所有IP
server_addr.sin_port=htons(SERVER_PORT);//绑定端口号
bind(sock,(struct sockaddr *)&server_addr,sizeof(server_addr));//绑定IP和端口
listen(sock,128);//监听客户端
printf("等待客户端的连接\n");
struct sockaddr_in client;
int client_sock, len;
char client_ip[32];//用来存客户端IP和端口 打印
// char buf[256];//用来接客户端的数据
socklen_t client_addr_len;
client_addr_len = sizeof(client);
client_sock = accept(sock, (struct sockaddr*)&client, &client_addr_len);
printf("client ip:%s\t port:%d\n",
inet_ntop(AF_INET,&client.sin_addr.s_addr,client_ip,sizeof(client_ip)),
ntohs(client.sin_port));
send(client_sock, buf_send, strlen(buf_send), 0);//建立连接成功,给客户端发一条信息
//创建线程用于收发
pthread_t send_tid, recv_tid;
pthread_create(&send_tid, NULL, sendMsg, (void *)&client_sock);
pthread_create(&recv_tid, NULL, recvMsg, (void *)&client_sock);
//此函数表示 子线程 结束 才能执行 主线程中后边的函数(防止子线程被中断)
pthread_join(send_tid, NULL);
pthread_join(recv_tid, NULL);
close(client_sock);
close(sock);
printf("finshed!\n");
return 0;
}
重点:编译的时候 一定要加 -lpthread (多线程)
结果:
后边有时间会接着改进,调试多人聊天模式,
有兴趣的可以一起来讨论交流,
待续。。。