简单的聊天室(UDP)
UDP编程步骤
1--创建数据报套接字 socket() : SOCK_DGRAM.
2--绑定地址信息. bind() . struct sockaddr_in.
3--recvfrom() 与 sendto() 适用于udp协议
4--关闭套接字close().
使用的f发送接收函数
ssize_t recvfrom(int socket, void *buffer, size_t length,
int flags, struct sockaddr *address,
socklen_t *address_len);
{
socket: 套接字;
buffer: 存放接受数据空间首地址.
length: 接受数据的字节大小
flags: 设置数据接受的模式.通常为0 缺省模式.
address: 存放客户端的地址信息.
如果不需要了解客户端信息则为NULL
address_len: 客户端的地址信息长度(传递的是地址)
}
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#define N 32
#define M 256
#define L 0x1
#define C 0x2
#define Q 0x3
typedef struct{
int type;
char name[N];
char text[M];
}MSG;
#define LEN sizeof(MSG)
typedef struct node{
struct sockaddr_in addr;
struct node *next;
}linknode,*linklist;
#define err_log(log)\
do{\
perror(log);\
exit(1);\
}while(0)
typedef struct sockaddr_in SA;
linklist create_list(void);
void do_login(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
void do_chat(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
void do_quit(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr,clientaddr;
socklen_t len=sizeof(SA);
bzero(&serveraddr,len);
MSG msg;
pid_t pid;
linklist H;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
{
err_log("fail to socket:");
}
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(6666);
serveraddr.sin_addr.s_addr=inet_addr("0.0.0.0");
if(bind(sockfd,(SA*)&serveraddr,len)<0)
{
err_log("fail to bind:");
}
pid=fork();
if(pid<0)
{
err_log("fail to fork:");
}
else if(pid==0)
{
bzero(&msg,LEN);
strcpy(msg.name,"server");
msg.type=C;
while(1)
{
fgets(msg.text,M,stdin);
msg.text[strlen(msg.text)-1]='\0';
sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
}
}
else
{
while(1)
{
H=create_list();
while(1)
{
recvfrom(sockfd,&msg,LEN,0,(SA*)&clientaddr,&len);
switch(msg.type)
{
case L:
do_login(sockfd,clientaddr,H,&msg);
break;
case C:
do_chat(sockfd,clientaddr,H,&msg);
break;
case Q:
do_quit(sockfd,clientaddr,H,&msg);
break;
default:
puts("error!");
break;
}
}
}
}
return 0;
}
linklist create_list(void)
{
linklist H;
if((H=(linklist)malloc(sizeof(linknode)))==NULL)
{
perror("fail to malloc:");
return NULL;
}
H->next=NULL;
return H;
}
void do_login(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)
{
linklist p=H->next;
linklist q;
sprintf(msg->text,"%s login.....",msg->name);
socklen_t len=sizeof(SA);
while(p)
{
sendto(sockfd,msg,LEN,0,(SA*)&p->addr,len);
p=p->next;
}
if((q=(linklist)malloc(sizeof(linknode)))==NULL)
{
perror("fail to malloc:");
return;
}
q->addr=clientaddr;
q->next=H->next;
H->next=q;
puts(msg->text);
}
void do_chat(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)
{
linklist p=H->next;
char buf[M]={0};
sprintf(buf,"%s said:%s",msg->name,msg->text);
strcpy(msg->text,buf);
socklen_t len=sizeof(SA);
while(p)
{
if(memcmp(&clientaddr,&p->addr,sizeof(clientaddr))!=0)
{
sendto(sockfd,msg,LEN,0,(SA*)&p->addr,len);
}
p=p->next;
}
puts(msg->text);
}
void do_quit(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)
{
linklist p=H;
linklist q;
sprintf(msg->text,"%s offline..........",msg->name);
socklen_t len=sizeof(SA);
while(p->next)
{
if(memcmp(&clientaddr,&p->next->addr,sizeof(clientaddr))==0)
{
q=p->next;
p->next=q->next;
free(q);
q=NULL;
}
else
{
sendto(sockfd,msg,LEN,0,(SA*)&p->next->addr,len);
p=p->next;
}
}
puts(msg->text);
}
客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#define N 32
#define M 256
#define L 0x1
#define C 0x2
#define Q 0x3
typedef struct{
int type;
char name[N];
char text[M];
}MSG;
#define LEN sizeof(MSG)
#define err_log(log)\
do{\
perror(log);\
exit(1);\
}while(0)
typedef struct sockaddr SA;
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr;
socklen_t len=sizeof(SA);
bzero(&serveraddr,len);
MSG msg;
pid_t pid;
if(argc!=3)
{
fprintf(stderr,"user:%s ip port",argv[0]);
return -1;
}
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)
{
err_log("fail to socket:");
}
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
puts("====================client login=================");
msg.type=L;
puts("input name>>>");
fgets(msg.name,N,stdin);
msg.name[strlen(msg.name)-1]='\0';
sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
pid=fork();
if(pid<0)
{
err_log("fail to fork:");
}
else if(pid==0)
{
while(1)
{
fgets(msg.text,M,stdin);
msg.text[strlen(msg.text)-1]='\0';
if(strncmp(msg.text,"quit",4)==0)
{
msg.type=Q;
sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
close(sockfd);
kill(getppid(),SIGKILL);
exit(0);
}
else
{
msg.type=C;
sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
}
}
}
else
{
while(1)
{
recvfrom(sockfd,&msg,LEN,0,(SA*)&serveraddr,&len);
printf("%s\n",msg.text);
}
}
return 0;
}