Udp编程过程
Sento不会阻塞
实现聊天室效果
上线
聊天
下线
服务端需要一个地址,去保留名字和ip地址
交互的时候发结构体
下面这个宏只能在c语言里使用
ser.sin_port = htons(50000);
上面是端口号50000以上,两边要一样
这里是不要让udp发的太快,发个东西过去
收和发的时候次数要一致
无状态的
为什么右边写在里面比较结束标志
验证了udp发送接收的数据是有边界
Netstat可以查看网络状态
服务器端
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {CMD_LOGIN,CMD_CHAT,CMD_LOGOUT}TYPE;
typedef struct
{
TYPE type;
char name[50];
char context[128];
}MSG;
typedef struct
{
struct sockaddr_in cli;
int flag; // 0 free 1 occu
}LIST;
#define MAX 10
LIST list[MAX]={0};
int do_login(int sockfd,MSG* msg,struct sockaddr_in* cli)
{
int i = 0 ;
for(i=0;i<MAX;i++)
{
if(1 == list[i].flag )
{
sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
}
}
for(i=0;i<MAX;i++)
{
if(0 == list[i].flag )
{
list[i].flag =1;
//list[i].cli = *cli;
memcpy(&list[i].cli,cli,sizeof(*cli));
break;
}
}
return 0;
}
int do_chat(int sockfd, MSG* msg,struct sockaddr_in*cli)
{
int i = 0 ;
for(i=0;i<MAX;i++)
{
if(1 == list[i].flag && 0!=memcmp(&list[i].cli,cli,sizeof(*cli)) )
{
sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
}
}
}
int do_logout(int sockfd, MSG* msg,struct sockaddr_in*cli)
{
return 0;
}
int main(int argc, char *argv[])
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
// man 7 ip
struct sockaddr_in ser,cli;
bzero(&ser,sizeof(ser));
bzero(&cli,sizeof(cli));
ser.sin_family = AF_INET;
// 大小端转化 host to net short
ser.sin_port = htons(50000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = bind(sockfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
perror("bind");
exit(1);
}
socklen_t len = sizeof(cli);
MSG msg;
while(1)
{
bzero(&msg,sizeof(msg));
recvfrom(sockfd,&msg,sizeof(msg),0,(SA)&cli,&len);
switch(msg.type)
{
case CMD_LOGIN:
do_login(sockfd,&msg,&cli);
break;
case CMD_LOGOUT:
do_logout(sockfd,&msg,&cli);
break;
case CMD_CHAT:
do_chat(sockfd,&msg,&cli);
break;
}
}
close(sockfd);
return 0;
}
用户端
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {CMD_LOGIN,CMD_CHAT,CMD_LOGOUT}TYPE;
typedef struct
{
TYPE type;
char name[50];
char context[128];
}MSG;
int main(int argc, char *argv[])
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
// man 7 ip
struct sockaddr_in ser,cli;
bzero(&ser,sizeof(ser));
ser.sin_family = AF_INET;
// 大小端转化 host to net short
ser.sin_port = htons(50000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t len = sizeof(cli);
MSG msg;
char name[50]={0};
printf("input name:");
fgets(name,sizeof(name),stdin);
name[strlen(name)-1]='\0';
msg.type = CMD_LOGIN;
strcpy(msg.name ,name);
strcpy(msg.context,"login");
sendto(sockfd,&msg,sizeof(msg),0,(SA)&ser,sizeof(ser));
pid_t pid = fork();
if(pid>0)
{
while(1)
{
bzero(&msg,sizeof(msg));
recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
printf("%s:%s\n",msg.name,msg.context);
}
}
else if(0==pid)
{
while(1)
{
printf("to all");
char buf[128]={0};
strcpy(msg.name,name);
msg.type = CMD_CHAT;
fgets(msg.context,sizeof(msg.context),stdin);//#quit
msg.context[strlen(msg.context)-1]='\0';
if(0==strcmp(msg.context,"#quit"))
{
msg.type = CMD_LOGOUT;
strcpy(msg.context,"CMD_LOGOUT");
}
sendto(sockfd,&msg,sizeof(msg),0,(SA)&ser,sizeof(ser));
}
}
else
{
perror("fork");
exit(1);
}
close(sockfd);
return 0;
}