本期和大家分享的是使用UDP实现聊天室的功能,本期日常小项目实现的是使用socket套接字实现UDP编程,使得能够进行通信;
使用到的主要函数接口有socket,bind,sendto,recvfrom,htons,inet_addr等在网络通信中需要用到的函数接口,在后续的TCP通信中也会使用到;下面带大家来看下具体实现:
1.主要分为两个进程,每个进程中都有两个线程负责收发;功能在代码注释中;
#include "head.h"
pthread_t tid1;
pthread_t tid2;
int sockfd = -1; //socket通信文件描述符
ssize_t nsize = 0;
char name[32]; //存储用户姓名
void *sendfun(void *arg)
{
msg_t tmpmsg;
struct sockaddr_in recvaddr; //存放协议族端口号以及ip地址的结构体
recvaddr.sin_family = AF_INET; //IPV4协议族
recvaddr.sin_port = htons(50001); //讲整形变量的端口号转变成网络字节序(因为整数一般存储方式为小端存储,但是IPV4有它特定的网络字节序)
recvaddr.sin_addr.s_addr = inet_addr("192.168.209.129"); //将点分十进制转化为IPV4能够识别的二进制数
while(1)
{
memset(&tmpmsg, 0, sizeof(tmpmsg.mytext));
strcpy(tmpmsg.name, name); //拷贝主进程中的用户昵称
gets(tmpmsg.mytext); //接收需要发送的消息
nsize = sendto(sockfd, &tmpmsg, sizeof(tmpmsg), 0, (struct sockaddr *)(&recvaddr), sizeof(recvaddr)); //发送消息
if (-1 == nsize)
{
perror("fail to sendto");
return NULL;
}
if (!strcmp(tmpmsg.mytext, "q")) //发送q结束聊天
{
break;
}
}
close(sockfd);
pthread_cancel(tid2);
return NULL;
}
void *recvfun(void *arg)
{
msg_t tmpmsg;
while (1)
{
memset(&tmpmsg, 0, sizeof(msg_t));
nsize = recvfrom(sockfd, &tmpmsg, sizeof(msg_t), 0, NULL, NULL); //接收消息
if (-1 == nsize)
{
perror("fail to recvfrom");
return NULL;
}
if (!strcmp(tmpmsg.mytext, "q"))
{
break;
}
printf("%s:%s\n", tmpmsg.name, tmpmsg.mytext);
}
close(sockfd);
pthread_cancel(tid1);
return NULL;
}
int main(int argc, const char *argv[])
{
int ret = 0;
struct sockaddr_in senaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
{
perror("fail to sockfd");
return -1;
}
senaddr.sin_family = AF_INET;
senaddr.sin_port = htons(50000);
senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");
ret = bind(sockfd, (struct sockaddr *)&senaddr, sizeof(senaddr)); //绑定自己的端口号和IP(清楚本进程是谁)
if (-1 == ret)
{
perror("fail to bind");
return -1;
}
printf("请输入您的昵称:");
gets(name);
putchar('\n');
pthread_create(&tid1, NULL, sendfun, NULL);
pthread_create(&tid2, NULL, recvfun, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
2.第二个进程和第一个进程非常相似,但是小伙伴们必须理解你在给谁发数据,所以必须把IP地址和端口号理解清楚;
#include "head.h"
pthread_t tid1;
pthread_t tid2;
int sockfd = -1;
struct sockaddr_in recvaddr;
char tmpbuff[1024] = {0};
int ret = 0;
ssize_t nsize = 0;
char name[32];
void *sendfun(void *arg)
{
msg_t tmpmsg;
struct sockaddr_in senaddr;
senaddr.sin_family = AF_INET;
senaddr.sin_port = htons(50000);
senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");
while(1)
{
memset(&tmpmsg, 0, sizeof(msg_t));
strcpy(tmpmsg.name, name);
gets(tmpmsg.mytext);
nsize = sendto(sockfd, &tmpmsg, sizeof(msg_t), 0, (struct sockaddr *)(&senaddr), sizeof(senaddr));
if (-1 == nsize)
{
perror("fail to sendto");
return NULL;
}
if (!strcmp(tmpmsg.mytext, "q"))
{
break;
}
}
close(sockfd);
pthread_cancel(tid2);
return NULL;
}
void *recvfun(void *arg)
{
msg_t tmpmsg;
while (1)
{
memset(&tmpmsg, 0, sizeof(tmpmsg));
nsize = recvfrom(sockfd, &tmpmsg, sizeof(msg_t), 0, NULL, NULL);
if (-1 == nsize)
{
perror("fail to recvfrom");
return NULL;
}
if (!strcmp(tmpmsg.mytext, "q"))
{
break;
}
printf("%s:%s\n", tmpmsg.name, tmpmsg.mytext);
}
close(sockfd);
pthread_cancel(tid1);
return NULL;
}
int main(int argc, const char *argv[])
{
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
{
perror("fail to sockfd");
return -1;
}
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(50001);
recvaddr.sin_addr.s_addr = inet_addr("192.168.209.129");
ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
if (-1 == ret)
{
perror("fail to bind");
return -1;
}
printf("请输入昵称:");
gets(name);
putchar('\n');
pthread_create(&tid1, NULL, sendfun, NULL);
pthread_create(&tid2, NULL, recvfun, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
进行双向通信的运行结果展示一下:
以上内容就是本期的分享内容,希望通过这个小项目可以让大家理解UDP通信中最基本的函数操作接口;不懂就问哦!