使用udp进行通信
UDP chat
头文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
服务端server
typedef struct sockaddr *(SA);
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
perror("socket");
return 1;
}
struct sockaddr_in server,client;
bzero(&server,sizeof(server));
bzero(&client,sizeof(client));
server.sin_family = AF_INET;
server.sin_port = htons(50000);
server.sin_addr.s_addr = 0;
int ret = bind(sockfd,(SA)&server,sizeof(server));
if(-1 == ret)
{
perror("bind");
exit(1);
}
char buf[512] = {0};
socklen_t len = sizeof(client);
recvfrom(sockfd,buf,sizeof(buf),0,(SA)&client,&len);
printf("cli addr:%s port:%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
pid_t pid = fork();
if(pid>0)
{
while(1)
{
bzero(buf,sizeof(buf));
recvfrom(sockfd,buf,sizeof(buf),0,(SA)&client,&len);
if(0==strcmp(buf,"#quit\n"))
{
kill(pid,2);
exit(1);
}
printf("from cli:%s\n",buf);
fflush(stdout);
}
}
else if(0 == pid)
{
while(1)
{
bzero(buf,sizeof(buf));
printf("to cli:");
fgets(buf,sizeof(buf),stdin);
sendto(sockfd,buf,strlen(buf),0,(SA)&client,sizeof(client));
if(0 == strcmp(buf,"#quit\n"))
{
kill(getppid(),2);
exit(1);
}
}
}
else
{
perror("fork");
exit(1);
}
return 0;
}
客户端client
typedef struct sockaddr * (SA);
struct sockaddr_in server;
void* th1(void* arg)
{
int sockfd = *(int*)arg;
while(1)
{
char buf[512]={0};
recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
if(0 == strcmp(buf,"#quit\n"))
{
exit(0);
}
printf("from ser:%s\n",buf);
}
return NULL;
}
void* th2(void* arg)
{
int sockfd = *(int*)arg;
while(1)
{
char buf[512]={0};
printf("to ser:");
fgets(buf,sizeof(buf),stdin);
sendto(sockfd,buf,strlen(buf),0,(SA)&server,sizeof(server));
if(0 == strcmp("#quit\n",buf))
{
exit(0);
}
}
return NULL;
}
int main(int argc, char *argv[])
{
int sockfd =socket(AF_INET,SOCK_DGRAM ,0);
if(-1 == sockfd)
{
perror("socket");
return 1;
}
//set ip port man 7 ip
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(50000);// >50000 host to net short
server.sin_addr.s_addr =0;
char buf[512]="@_@";
sendto(sockfd,buf,strlen(buf),0,(SA)&server,sizeof(server));
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,th1,&sockfd);
pthread_create(&tid2,NULL,th2,&sockfd);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
函数
socket
int socket(int domain, int type, int protocol);
domain
: 指定通信协议族,这里使用的是AF_INET
,表示使用IPv4协议。type
: 指定套接字类型,SOCK_DGRAM
表示使用数据报套接字,也就是UDP协议。protocol
: 通常为0
,表示选择默认协议,对于SOCK_DGRAM
来说,默认的协议就是UDP。
创建udp套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0)
sockfd = socket(int socket_family, int socket_type, int protocol);
bzero
bzero
是一个用于将指定内存区域清零的函数,通常用于初始化数据结构,以确保它们不包含任何未初始化的数据。
void bzero(void *s, size_t n);
s
: 指向需要清零的内存区域的指针。n
: 要清零的字节数。
bzero
将从指针s
所指向的内存区域开始的n
个字节全部设置为零。
struct sockaddr_in server;
bzero(&server, sizeof(server));
bzero
在网络编程中初始化 sockaddr_in
结构体:
bzero
将 server
结构体的所有字节都设置为零,确保其中的每个字段都被正确初始化。使用 bzero
比逐个字段手动初始化要简单得多。
sendto
sendto
是一个用于发送数据到指定目标地址的函数,常用于UDP(数据报套接字)的网络编程。与TCP不同,UDP是无连接的协议,使用sendto
函数可以在不建立连接的情况下发送数据。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
sockfd
: 套接字文件描述符,表示通过哪个套接字发送数据。buf
: 指向要发送的数据的指针。len
: 要发送的数据的长度(字节数)。flags
: 一般设置为0
,除非需要设置特殊的发送选项。dest_addr
: 指向目的地址的指针,即目标主机的地址和端口信息。这个地址通常使用sockaddr_in
结构体表示。addrlen
:dest_addr
结构体的大小,通常使用sizeof(struct sockaddr_in)
。
recvfrom
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
sockfd
: 套接字文件描述符,指定从哪个套接字接收数据。buf
: 指向接收数据的缓冲区指针。len
: 缓冲区的大小(字节数),即可以接收的最大数据量。flags
: 通常设置为0
,除非需要特殊的接收行为(如非阻塞模式)。src_addr
: 用于存储发送方的地址信息的结构体指针(通常是sockaddr_in
类型)。如果不关心发送方地址,可以设置为NULL
。addrlen
: 一个指向socklen_t
类型变量的指针,用于存储发送方地址的长度。如果src_addr
是NULL
,这个参数可以忽略。
bind
bind
函数在网络编程中用于将一个套接字(socket)绑定到一个特定的IP地址和端口号上。通常在服务器端程序中使用,以指定该服务器在某个IP地址和端口上监听客户端的连接或数据。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd
: 套接字文件描述符,指示要绑定的套接字。addr
: 指向包含IP地址和端口信息的sockaddr
结构体的指针。对于IPv4,通常使用sockaddr_in
结构体来表示。addrlen
:addr
结构体的大小,通常使用sizeof(struct sockaddr_in)
。
- 服务器端:
bind
是服务器端程序中必须的步骤之一,它将服务器的套接字绑定到一个特定的IP地址和端口上,以便客户端能够通过这个地址和端口与服务器通信。 - 客户端:对于客户端程序,通常不需要手动调用
bind
,因为系统会自动为客户端分配一个临时端口。然而,如果客户端希望指定特定的源IP地址或端口,也可以使用bind
。