-
一、UDP服务器
-
创建
-
1、socket --创建套接字
-
2、bind--绑定
-
3、recvfrom--等待接收数据(无连接)(TCP用recv(有连接的))
- #include <sys/types.h>
- #include <sys/socket.h>
- ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
- struct sockaddr *src_addr, socklen_t *addrlen);
-
功能:从sockfd指向的端点读取数据,如果sockfd所指向的端点没有数据则阻塞
-
参数:
- sockfd:socket创建的套接字
- buf : 接收数据的缓存区
- len :希望从sockfd里面读取len个字节的数据
- fiags :一般传0
- src_addr :用于保存发送方的IP地址
- addrlen:地址结构体的长度(需要计算出来)
-
返回值:
- >0 :实际从sockfd中读取到的字节数
- -1 :失败
-
-
功能代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("spcket!\n");
return -1;
}
//绑定
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8989);
saddr.sin_addr.s_addr = INADDR_ANY;
if(-1 == bind(sockfd, (struct sockaddr *)&saddr,sizeof(saddr) ))
{
perror("bind\n");
return -1;
}
//等待接收数据
char buf[64] = {0};
while(1)
{
recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
printf("buf: %s\n", buf);
memset(buf, 0, sizeof(buf));
}
return 0;
}
二、UDP客户端
-
创建客户端
-
1、创建套接字socket
- int sockfd = socket(AF_INET, SOCK_DGRAM,0);
-
2、发送数据----sendto
- #include <sys/types.h>
- #include <sys/socket.h>
- ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
-
功能:
-
使用sockfd发送数据将buf里面的前len个字节的数据发送到dest_addr 指定的IP和端口
-
参数:
- sockfd:socket创建的套接字
- buf : 发送数据的缓存区
- len :要发送的字节数
- fiags :一般填0
- dest_addr :对端的地址
- addrlen:地址结构体的大小(需要计算出来)
-
返回值:
- >0 :实际从sockfd中读取到的字节数
- -1 :失败
-
功能代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("socket error!\n");
return -1;
}
//发送数据
char buf[64] = {0};
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8989);
saddr.sin_addr.s_addr = inet_addr("192.168.7.219");
while(1)
{
read(0, buf, sizeof(buf));
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&saddr, sizeof(saddr));
memset(buf, 0, sizeof(buf));
}
return 0;
}
三、多个客户端的聊天系统设计
效果展示:
客户端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("socket error!\n");
return -1;
}
//发送数据
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8989);
saddr.sin_addr.s_addr = inet_addr("192.168.7.219");
pid_t pid = fork();
if(0 == pid)//子进程负责接收消息
{
char sendbuf[64] = {0};
while(1)
{
read(0, sendbuf, sizeof(sendbuf));
sendto(sockfd, sendbuf, sizeof(sendbuf), 0, (struct sockaddr*)&saddr, sizeof(saddr));
memset(sendbuf, 0, sizeof(sendbuf));
}
}
else if(0 < pid)
{
char recvbuf[64] = {0};
while(1)
{
recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, NULL, NULL);
printf("recvbuf: %s\n", recvbuf);
memset(recvbuf, 0, sizeof(recvbuf));
}
}
return 0;
}
服务器代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <string.h>
#define MAX 50
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == sockfd)
{
perror("spcket!\n");
return -1;
}
//绑定
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8989);
saddr.sin_addr.s_addr = INADDR_ANY;
if(-1 == bind(sockfd, (struct sockaddr *)&saddr,sizeof(saddr) ))
{
perror("bind\n");
return -1;
}
//等待接收数据
char buf[64] = {0};
struct sockaddr_in caddr;
int len = sizeof(caddr);
unsigned int conn = 0;//保存在线用户人数
struct sockaddr_in member[MAX];//保存在线用户的地址信息
memset(member, 0, sizeof(member));
int flag = 0; //用于判断是否保存当前caddr的地址, 0保存,1不保存
while(1)
{
flag = 0;
//接收客户端的数据并保存客户端地址
recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&caddr, &len);
if(0 == conn)//在线人数为0
{
member[conn] = caddr;
conn++;
}
else
{
for(int i = 0; i < conn; i++) //判断member是否已经保存了caddr的地址
{
if(caddr.sin_addr.s_addr == member[i].sin_addr.s_addr && caddr.sin_port == member[i].sin_port)
flag = 1;
}
if(0 == flag)
{
member[conn] = caddr;
conn ++;
}
}
//转发消息
for(int i = 0; i < conn; i++)//判断转发消息的客户端的ip地址是否已经在member数组中
{
if(caddr.sin_addr.s_addr == member[i].sin_addr.s_addr && caddr.sin_port == member[i].sin_port)
continue;
sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&member[i], sizeof(struct sockaddr_in));
}
printf("buf: %s\n", buf);
memset(buf, 0, sizeof(buf));
}
return 0;
}