本文已参与「新人创作礼」活动,一起开启掘金创作之路。
套接字基础
套接字类型
Linux支持多种套接字类型,即应用程序希望的通信服务类型
- SOCKET_STREAM:双向可靠数据流,对应TCP
- SOCKET_DGRAM :双向不可靠数据报,对应UDP
- SOCKET_RAW:是低于传输层的低级协议或物理网络提供的套接字类型,可以访问内部网络接口。例如接收和发送ICMP报文
UDP Socket编程的过程
实现UDP套接字基本步骤分为服务器端和客户端两部分:
服务器端:
- 创建套接字;
- 绑定套接字;
- 读取客户端发过来的数据;
- 向客户端写数据;
- 关闭套接字。
客户端:
- 创建套接字;
- 向服务器发送数据;
- 读取服务器发来的数据;
- 关闭套接字。
适用范围
部分满足以下几点要求时,应该用UDP:
- 面向数据报
- 网络数据大多为短消息
- 拥有大量Client 对数据安全性无特殊要求
- 网络负担非常重,但对响应速度要求高
源码
gcc编译后使用
gcc -o udps udps.c
gcc -o udpc udpc.c
./udps
./udpc
server
// udps.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8900
#define MAXSIZE 1024
int main(){
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
char send_buf[MAXSIZE];
char recv_buf[MAXSIZE];
socklen_t len;
int recvnum;
int sockfd;
if(-1==(sockfd = socket(AF_INET, SOCK_DGRAM, 0))){
perror("create error!\n");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
if(-1==bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr))){
perror("bind error!\n");
return -1;
}
while(1){
memset(recv_buf, 0, MAXSIZE);
memset(send_buf, 0, MAXSIZE);
len = sizeof(client_addr);
if(-1==(recvnum = recvfrom(sockfd, recv_buf, MAXSIZE, 0, (struct sockaddr*)&client_addr, &len))){
perror("receive error!\n");
return -1;
}
printf("client:[%dB]%s\n", strlen(recv_buf), recv_buf);
sprintf(send_buf, "[%dB]%s\n", strlen(recv_buf), recv_buf);
sendto(sockfd, send_buf, MAXSIZE, 0, (struct sockaddr*)&client_addr, len);
}
close(sockfd);
return 0;
}
client
// udpc.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8900
#define MAXSIZE 1024
int main(){
int sockfd;
socklen_t len;
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
char send_buf[MAXSIZE];
char recv_buf[MAXSIZE];
if(-1==(sockfd = socket(AF_INET, SOCK_DGRAM, 0))){
perror("create error!\n");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
while(1)
{
len = sizeof(server_addr);
memset(send_buf, 0, MAXSIZE);
memset(recv_buf, 0, MAXSIZE);
printf("client:");
gets(send_buf);
sendto(sockfd, send_buf, MAXSIZE, 0, (struct sockaddr*)&server_addr, len);
recvfrom(sockfd, recv_buf, MAXSIZE, 0, (struct sockaddr*)&client_addr, &len);
printf("server:%s\n",recv_buf);
}
close(sockfd);
return 0;
}
运行样例
server会返回接收到的信息和大小