最近学习网络编程,写了一个聊天室,基本功能已经实现,还有待优化的部分
服务器端
首先说下大概的功能吧
1. 服务器开始运行,绑定好IP跟端口
2.服务器开始监听客户端的链接
3.如果有客户端链接服务器,那么服务器记录下客户端的地址,
然后分配一个线程用于跟客户端通信
4.服务器把接受到的消息分别转发给其他客户端,实现共享聊天内容
4.1.服务器继续监听其他客户端的链接。
#include"server.h"
static int sockid,i,end;
void fa(int signo)
{
printf("\r服务器正在关闭>>>>>\n");
sleep(2);
close(sockid);
exit(0);
}
typedef struct
{
struct sockaddr_in c_sockaddr;
int c_sockid;
pthread_t tid;
}c_addr;
//建立套接字绑定端口
int s_bind(void);
int s_pthread_create(int sockid);
void * task(void *p);
int main(int argc,char * agrv[])
{
printf("服务器开始运行\n");
//信号处理
signal(2,fa);
//建立套结字,绑定借口
int sockid = s_bind();
if(-1 == sockid)
printf("建立绑定套结字失败\n");
//开始监听客户端
listen(sockid,100);
//为客户端分配线程
s_pthread_create(sockid);
//exit(0);
exit(0);
}
int s_bind(void)
{
//生成套结字
sockid = socket(AF_INET,SOCK_STREAM,0);
//准备地址信息
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//绑定服务短地址
int res = bind(sockid,(struct sockaddr *)&addr,sizeof(addr));
if(res == -1)
{
perror("bind"),exit(-1);;
}
return sockid;
}
int s_pthread_create(int sockid)
{
//定义结构题,用于存储客户端的地址与通信编号
c_addr c_c_addr[100];
while(i < 100){
//初始化c_c_addr
c_c_addr[i].c_sockid = 0;
//准备套结字接收客户端地址
socklen_t len = sizeof(c_c_addr[i].c_sockaddr);
//接受到客户端信息
c_c_addr[i].c_sockid = accept(sockid,(struct sockaddr *)&c_c_addr[i].c_sockaddr,&len);
if(c_c_addr[i].c_sockid == -1)
perror("accept"),exit(-1);
//分配线程
//pthread_t tid;
printf("客户端:%s上线\n",inet_ntoa(c_c_addr[i].c_sockaddr.sin_addr));
pthread_create(&c_c_addr[i].tid,NULL,task,(void *)c_c_addr);
usleep(500000);
i++;
}
}
void * task(void *p)
{
int n = i;
c_addr * c_c_addr = p;
//接收客户端发来的消息
char buf[100] = {0};
while(1)
{
printf("n == %d\n",n);
if(0 >= read(c_c_addr[n].c_sockid,buf,sizeof(buf)))
{
c_c_addr[n].c_sockid = -1;
printf("客户端:%s下线\n",inet_ntoa(c_c_addr[n].c_sockaddr.sin_addr));
pthread_exit(&c_c_addr[n].tid);
}
printf("来自客户端的消息%s\n",buf);
char *p = buf;
//转发给其他客户端
int j = 0;
while(j < i)
{
//判断是否是自己线程,
if(c_c_addr[j].tid == pthread_self() || c_c_addr[j].c_sockid == -1)
{
j++;
continue;
}
if(0 >= send(c_c_addr[j].c_sockid,buf,strlen(buf) + 1,0))
{
c_c_addr[j].c_sockid = -1;
}
j++;
}
//推出线程
}
}
客户端
1.客户端初始化链接服务器的地址
2.链接成功后客户端分配一个线程用于接受服务器
发送来的消息
3.客户端主线程用于接收用户输入的内容发送给服务器
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<semaphore.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<pthread.h>
#include<unistd.h>
#define PORT 8888
int sockid;
void fa(int signo)
{
printf("\r客户端马上关闭\n");
close(sockid);
sleep(1);
exit(0);
}
int c_connect(void);
void scan(char arr[]);
void talk(void);
void *task(void *p);
void speak(char *name);
int main()
{
signal(2,fa);
//与服务器建立链接
sockid = c_connect();
//输入用户昵称
char name[20];
printf("请输入用户姓名\n");
scanf("%s",name);
//接收服务器发来的消息
talk();
//吧用户输入的信息发送给服务器端
speak(name);
}
void speak(char *name)
{
while(1)
{
//sleep(1);
printf("请输入信息:\n");
char cuf[100];
fflush(stdin);
//scanf("%*[^\n]");
//scanf("%*c");
//fwrite(cuf,1,1,stdin);
scanf("%s",cuf);
// fgets(cuf,100,stdin);
fflush(stdin);
//cuf[strlen(cuf)-1] = '\0';
char buf[1000];
sprintf(buf,"%s:%s",name,cuf);
int res;
if( 0 >= send(sockid,buf,strlen(buf) + 1,0))
//printf("res = %d\n",res);
perror("服务器关闭"),exit(-1);
}
}
void *task(void *p)
{
char buf[100];
while(1)
{
if(0 > recv(sockid,buf,sizeof(buf),0))
perror("recv"),exit(0);
printf("%s\n",buf);
}
}
void talk(void)
{
//创建线程用于接受服务器的消息
pthread_t tid;
pthread_create(&tid,NULL,task,NULL);
}
void scan(char arr[])
{
printf("请输入用户昵称\n");
scanf("%s",arr);
fflush(stdin);
}
int c_connect(void)
{
int sockid = socket(AF_INET,SOCK_STREAM,0);
//准备服务器的地址信息
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//链接服务器地址
int res = connect(sockid,(struct sockaddr*)&addr,sizeof(addr));
if(-1 == res)
{
perror("connect"),exit(-1);
}
return sockid;
}