UDP(用户数据报协议)协议
- UDP协议是无连接的 : 只需知道对端IP和端口号就可以发送数据,不需要建立连接,双方感知不到对方的存在。
- UDP协议是不可靠的: 没有确认机制,不会对接收到的数据确认,就不知道对端是否收到。
- UDP协议是面向数据报的: 不能灵活的控制数据的读写次数和数量, 只能一次读完。
- UDP是支持全双工: 即双方可以同时进行读写操作。
UDP的缓存区
UDP没有真正意义上的发送缓存区,调用sendto将用户数据拷贝给内核,由内核执行后续动作。
UDP具有接收缓存区,缓存区满了之后,后续到来的数据将被丢弃。
UDP使用注意事项
在UDP首部中,16位UDP最大长度,最大为64K(包括UDP首部),如果传输数据大于64K需要在上层进行分割,接收端上层进行组装。
TCP(传输控制)协议
- TCP协议是面向连接
- TCP协议是可靠的
- TCP协议面向字节流
- TCP支持全双工
TCP是面向连接的
TCP协议传输前需要先建立连接,三次握手,释放连接,四次挥手。
TCP是可靠的
序号(按序到达)
确认重传机制
超时重传机制
连接管理
流量控制
拥塞控制
TCP面向字节流
TCP存在发送缓冲区和接收缓存区。即可以一次读1字节也可以一次读100字节,可随意读取,当然写也可以。
在发送数据时,如果数据太多会分成多个TCP的数据包发送出去,如果太少会等数量合适,或者合适的时机发送出去。
在接收数据时,也是从缓存区读取数据。
总结
UDP和TCP不存在那个好或者不好的问题,只是适合的场景不同。
一般UDP适合高速传输和实时性较高的场景。
一般TCP适合可靠传输的场景。
简单的基于UDP的 socket
//UDP
//UDP client
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int CreateSocket()
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
perror("sock");
exit(1);
}
return sock;
}
void client(int socket, const char* ip, const char* port)
{
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(port));
server.sin_addr.s_addr = inet_addr(ip);
char buf[1024];
struct sockaddr_in peer;
while(1)
{
printf("please Enter:");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);
if(s > 0)
{
sendto(socket, buf, sizeof(buf), 0\
, (struct sockaddr*)&server, sizeof(server));
}
socklen_t len = sizeof(peer);
ssize_t r = recvfrom(socket, buf, sizeof(buf), 0\
, (struct sockaddr*)&peer, &len);
if(r > 0)
{
buf[s] = 0;
printf("[%s : %d] server echo:%s",inet_ntoa(peer.sin_addr),\
ntohs(peer.sin_port), buf);
}
}
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("%s [ip : port]", argv[0]);
return 1;
}
int sock = CreateSocket();
client(sock, argv[1], argv[2]);
return 0;
}
// udp client
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define ERR_EXIT(x) do\
{ \
perror(x);\
exit(1);\
}while(0)
int CreateSocket(const char* ip,const char* port)
{
int sock = socket(AF_INET,SOCK_DGRAM, 0);
if(sock < 0)
{
ERR_EXIT("sock");
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(port));
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local, sizeof(local)) < 0)
{
ERR_EXIT("bind");
}
return sock;
}
void service(const int sock)
{
struct sockaddr_in local;
char buf[1024];
while(1)
{
socklen_t len = sizeof(local);
ssize_t ret = recvfrom(sock, buf, sizeof(buf), 0, \
(struct sockaddr*)&local, &len);
if(ret > 0)
{
buf[ret-1] = 0;
printf("[%s : %d]client: %s\n",\
inet_ntoa(local.sin_addr),ntohs(local.sin_port)\
,buf);
sendto(sock, buf, sizeof(buf), 0,\
(struct sockaddr*)&local, sizeof(local));
}
}
}
void UseSocket(const char* str)
{
printf("%s ip: port: \n", str);
}
int main(int agrc, char* argv[])
{
if(agrc != 3)
{
UseSocket(argv[0]);
return 1;
}
int socket = CreateSocket(argv[1], argv[2]);
service(socket);
return 0;
}
简单的基于TCP的 socket
//client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int startup(char* ip, char* port)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("sock");
exit(2);
}
struct sockaddr_in pr;
pr.sin_family = AF_INET;
pr.sin_port = htons(atoi(port));
//inet_pton(AF_INET, ip, &pr.sin_addr );
pr.sin_addr.s_addr = inet_addr(ip);
int ret = connect(sock, (struct sockaddr*)&pr, sizeof(pr));
if(ret < 0)
{
perror("connect");
exit(3);
}
printf("get connect\n");
return sock;
}
void client(int sock)
{
char buf[1024];
while(1)
{
memset(buf, 0, sizeof(buf));
printf("client Please enter: ");
fgets(buf, sizeof(buf), stdin);
if(strcmp(buf, "quit\n") == 0)
{
printf("client quit now!\n");
break;
}
write(sock, buf, strlen(buf)-1);
printf("wait....\n");
// int s = read(sock, buf, sizeof(buf)-1);
// buf[s] = 0;
// printf("server $: %s\n", buf);
}
close(sock);
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: %s [ip : port]\n", argv[0]);
return 1;
}
int sock = startup(argv[1], argv[2]);
client(sock);
return 0;
}
//server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
int startup(char* ip, char* port)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("sock");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(port));
local.sin_addr.s_addr = inet_addr(ip);
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
perror("bind");
close(sock);
exit(3);
}
if(listen(sock, 10) < 0)
{
perror("listen");
close(sock);
exit(4);
}
printf("bind and listen success...\n");
return sock;
}
void sock_server(int);
void* tcp_server(void *arg)
{
int sock = (int)arg;
sock_server(sock);
}
void sock_server(int sock)
{
char buf[1024];
int s ;
while(1)
{
printf("wait....\n");
s = read(sock, buf, sizeof(buf)-1);
if(s < 0)
{
perror("read");
exit(6);
}
else if(s == 0)
{
printf("connect --\n");
close(sock);
break;
}
else
{
buf[s] = 0;
printf("client #: %s\n", buf);
write(sock, buf, strlen(buf));
// printf("server Please enter: ");
// memset(buf, 0, sizeof(buf));
// fgets(buf, sizeof(buf)-1, stdin);
// write(sock, buf, sizeof(buf));
}
}
}
void service(int socket)
{
struct sockaddr_in peer;
char buf[1024];
char ip[40];
for(;;)
{
socklen_t len = sizeof(peer);
int sock = accept(socket, (struct sockaddr*)&peer, &len);
if(sock < 0)
{
perror("accept");
exit(5);
}
memset(ip, 0x0, sizeof(ip));
inet_ntop(AF_INET,&peer.sin_addr, ip, sizeof(ip));
printf("get connect [ip:%s port: %d]\n", ip, ntohs(peer.sin_port));
pthread_t tid;
if(pthread_create(&tid, NULL, tcp_server, (void*)sock) < 0)
{
perror("pthread_create");
exit(7);
}
pthread_detach(tid);
// pid_t pid = fork();
// if(pid < 0)
// {
// printf("fork error\n");
// }
// else if(pid == 0)
// {
// pid_t cpid = fork();
// if(cpid < 0)
// {
// printf("child fork error\n");
// }
// else if(cpid == 0)
// {
// close(socket);
// sock_server(sock);
// }
// else
// {
// exit(0);
// }
// }
// else
// {
// waitpid(pid, NULL, 0);
// close(sock);
//
// }
}
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("Usage: %s [ip : port]\n", argv[0]);
return 1;
}
int sock = startup(argv[1], argv[2]);
service(sock);
return 0;
}