网络聊天室
运行代码:
main.c
#include "link.h"
#define SER_PORT 8888
int main(int argc, const char *argv[])
{
if(argv[1]==NULL){
printf("请输入IP地址\n");
return 0;
}
//创建套接字文件
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd == -1){
perror("socket error");
return -1;
}
//设置端口快速重用
int reuse = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){
perror("setsockopt error");
return -1;
}
//创建用户信息头结点
usermsg_p H = node_head();
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(argv[1]);
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))==-1){
perror("bind error");
return -1;
}
H->cin=sin;
//IO 多路复用
struct pollfd pfd[2];
pfd[0].fd = 0;
pfd[0].events = POLLIN;
pfd[1].fd = sfd;
pfd[1].events=POLLIN;
//接受用户信息所用的结构体
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
usermsg user_msg;
usertext user_text;
char buf[200]="";
while(1){
poll(pfd,2,-1);
/***************输入**************************/
#if 1
if(pfd[0].revents==POLLIN){
//输出
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf)-1,stdin);
buf[strlen(buf)-1]=0;
ser_allput(H,sfd,buf);
}
#endif
/*******************输出*************************/
if(pfd[1].revents==POLLIN){
recvfrom(sfd,&user_text,sizeof(user_text),0,(struct sockaddr *)&cin,&socklen);
switch(user_text.type){
//上线
case 0:{
bzero(buf,sizeof(buf));
printf("[%s]登录成功\n",user_text.username);
sprintf(buf,"[%s]已上线",user_text.username);
ser_allput(H,sfd,buf);
insert_usermsg(H,cin,user_text.username);
};break;
//转发
case 1:{
bzero(buf,sizeof(buf));
sprintf(buf,"[%s]:%s",user_text.username,user_text.text);
printf("[%s]chat成功\n",user_text.username);
ser_output(H,sfd,buf,cin.sin_port);
break;
};
//下线
case 2:{
bzero(buf,sizeof(buf));
tail_usermsg(H,cin.sin_port);
printf("[%s]已下线\n",user_text.username);
sprintf(buf,"[%s]已下线",user_text.username);
ser_allput(H,sfd,buf);
};break;
}
}
//输出
}
/********************************************/
close(sfd);
return 0;
}
link.c
#include "link.h"
usermsg_p node_head(){
usermsg_p H=(usermsg_p)malloc(sizeof(usermsg));
if(NULL==H){
printf("创建失败\n");
return NULL;
}
H->next=NULL;
H->front=NULL;
return H;
}
usermsg_p node_create(struct sockaddr_in cin,char *username){
usermsg_p new = (usermsg_p)malloc(sizeof(usermsg));
if(new==NULL){
printf("创建新节点失败\n");
return NULL;
}
bzero(new->username,sizeof(new->username));
new->next=NULL;
new->front=NULL;
return new;
}
//插入用户信息 头插
void insert_usermsg(usermsg_p H,struct sockaddr_in cin,char *username){
if(NULL==H){
printf("头传入失败\n");
return;
}
usermsg_p new=node_create(cin,username);
if(new==NULL){
printf("创建新节点失败\n");
return;
}
new->next=H->next;
new->front = H;
H->next = new;
new->cin=cin;
strcpy(new->username,username);
}
//用户下线,删除 判断条件
void tail_usermsg(usermsg_p H,short int port){
printf("%d %d\n",__LINE__,ntohs(port));
if(NULL==H){
printf("指针传入失败\n");
return;
}
if(H->next==NULL){
return;
}
usermsg_p p = H->next;
while(p!=NULL){
if(ntohs(port)==ntohs((p->cin).sin_port)){
printf("%d %d\n",__LINE__,ntohs((p->cin).sin_port));
p->front->next = p->next;
if(p->next!=NULL)
p->next->front = p->front;
free(p);
return;
}
p=p->next;
}
printf("没找到用户数据,删除失败\n");
}
//功能:转发
#if 1
void ser_output(usermsg_p H,int sfd,char *text,short int port){
if(H==NULL){
printf("%d link.c 传输失败\n",__LINE__);
return;
}
usermsg_p p = H->next;
while(p!=NULL){
if(ntohs((p->cin).sin_port)==ntohs(port)){
p=p->next;
continue;
}
sendto(sfd,text,strlen(text)+1,0,(struct sockaddr *)&(p->cin),sizeof(p->cin));
p=p->next;
}
}
void ser_allput(usermsg_p H,int sfd,char *text){
if(NULL==H){
printf("%d H传入失败\n",__LINE__);
return;
}
if(H->next==NULL){
return;
}
usermsg_p p = H->next;
while(p!=NULL){
sendto(sfd,text,strlen(text)+1,0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
p=p->next;
}
}
#endif
//
link.h
#ifndef __LINK_H__
#define __LINK_H__
#include<myhead.h>
typedef struct usermsg{
char username[20];
struct sockaddr_in cin;
struct usermsg *next;
struct usermsg *front;
}usermsg,*usermsg_p;
typedef struct usertext{
char type; //客户端状态
char username[20];
char text[128];
}usertext,*usertext_p;
usermsg_p node_head();//创建头结点
usermsg_p node_create(struct sockaddr_in cin,char *username);//新节点、存放用户信息
void insert_usermsg(usermsg_p H,struct sockaddr_in cin,char *username);//插入用户信息
void tail_usermsg(usermsg_p H,short int port);//用户下线,删除
void ser_output(usermsg_p H,int sfd,char *text,short int port);
void ser_allput(usermsg_p H,int sfd,char *text);
#endif
客户端:
#include<myhead.h>
struct usertext{
char type;
char username[20];
char text[128];
};
int main(int argc, const char *argv[])
{
if(argv[1]==NULL){
printf("请输入IP地址\n");
return 0;
}
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd == -1){
perror("socket error");
return -1;
}
//前摇
struct sockaddr_in sin;
sin.sin_family = AF_INET;
struct usertext user_text;
char buf[200] = "";
int port=0;
user_text.type=0;
printf("请输入用户名>>>");
fgets(buf,sizeof(buf)-1,stdin);
buf[strlen(buf)-1]=0;
user_text.type=0;
strcpy(user_text.username,buf);
sin.sin_addr.s_addr = inet_addr(argv[1]);
printf("请输入服务器端口>>>");
scanf("%d",&port);
sin.sin_port = htons(port);
//发送连接请求
sendto(cfd,&user_text,sizeof(user_text),0,(struct sockaddr *)&sin,sizeof(sin));
user_text.type=1;
//IO多路复用 poll
struct pollfd pfd[2];
pfd[0].fd = 0;
pfd[0].events = POLLIN;
pfd[1].fd = cfd;
pfd[1].events = POLLIN;
int i = 0;
while(1){
poll(pfd,2,-1);
if(pfd[0].revents==POLLIN){
fgets(user_text.text,sizeof(user_text.text)-1,stdin);
if(0==i){i++;continue;}
user_text.text[strlen(user_text.text)-1]=0;
if(strcmp(user_text.text,"quit")==0){
user_text.type = 2;
sendto(cfd,&user_text,sizeof(user_text),0,(struct sockaddr *)&sin,sizeof(sin));
break;
}
sendto(cfd,&user_text,sizeof(user_text),0,(struct sockaddr *)&sin,sizeof(sin));
}
if(pfd[1].revents==POLLIN){
recv(cfd,buf,sizeof(buf)-1,0);
printf("%s\n",buf);
}
}
close(cfd);
return 0;
}
运行截图: