TCP和UDP的区别
1.TCP面向连接(如打电话要先拨号建立连接);
UDP是无连接的,即发送数据之前 不需要建立连接
2.TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3.TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4.每一条TCP连接智能是点到点的;UDP支持一对一,一对多,多对一,多对一和多对多的交互通信
5.TCP首部开销20字节;UDP的首部开销小,只有8个字节
6.TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
端口号的作用
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等等
这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。
实际上是通过“IP地址+端口号”来区分不同服务的。
端口提供了一种访问通道
服务器一般都是通过知名端口号来失败的。例如,对于每个TCP、IP实现来说,FTP服务的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69
字节序
与同一台计算机上的进程进行通信时,一般不用考虑字节序。字节序是一个处理器架构特性,用于指示像整数这样的大数据类型内部的字节是如何排序的
Little endian小端字节序
Big endian 大端字节序
网络字节序=大端字节序
Sockt服务器和客户端的开发步骤
1.创建套接字
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
// 返回值: 成功返回文件(套接字)描述符,失败返回-1
domain(域)确定通信的特性,包括地址格式
domain(域) | 描述 |
---|---|
AF_INET | IPv4因特网域 |
AF_INET6 | IPv6因特网域 |
AF_UNIX | UNIX域 |
AF_UPSPEC | 未指定 |
参数type确定套接字的类型,进一步确定通信特征
type(类型) | 描述 |
---|---|
SOCK_DGRAM | 固定长度的、无连接的、不可靠的报文传输 UDP |
SOCK_STREAM | 有序的、可靠的、双向的、面向连接的字节流 TCP |
SOCK_SEQPACKET | 固定长度的、有序的、可靠的、面向连接的报文传递 |
SOCK_RAW | IP协议的数据报接口 |
参数 protocol 通常是0 , 表示为给定的域和套接字类型选择默认协议。
protocol | |
---|---|
IPPROTO_TCP | TCP传输协议 |
IPPROTO_UDP | UDP传输协议 |
IPPROTO_SCTP | SCTP传输协议 |
IPPROTO_TIPC | TIPC传输协议 |
2.bind()添加IP号端口号
地址转换API
3.监听
4.连接
5.读取和写入
客户端的连接
例子:
服务器
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int s_fd;
int n_read;
int c_fd;
int mark=0;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
char msg[128]={0};
char readBuf[128]={0};
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc!=3){
printf("param is not good\n");
exit(-1);
}
//1.socket
s_fd=socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1){
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
//2.bind
//
bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
//4.accept
int clen=sizeof(struct sockaddr_in);
while(1){
c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd==-1){
perror("accept");
}
mark++;
printf("connect success!%s\n",inet_ntoa(s_addr.sin_addr));
if(fork()==0){
if(fork()==0){
while(1){
sprintf(msg,"welcome No.%d",mark);
write(c_fd,msg,strlen(msg));
sleep(3);
}
}
//5.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read=read(c_fd,readBuf,128);
if(n_read==-1){
perror("read");
}else{
printf("get success:%d\n%s\n",n_read,readBuf);
}
}
//6.write
break;
}
}
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int c_fd;
int n_read;
struct sockaddr_in c_addr;
char msg[128]={0};
char readBuf[128]={0};
memset(&c_addr,0,sizeof(struct sockaddr_in));
if(argc!=3){
printf("param is not good!\n");
exit(-1);
}
//1.socket
c_fd=socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1){
perror("socket");
exit(-1);
}
c_addr.sin_family=AF_INET;
c_addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
//2.connect
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))==-1){
perror("connect");
exit(-1);
}
while(1){
if(fork()==0){
while(1){
//3.write
memset(msg,0,sizeof(msg));
printf("input: \n");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
//4.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read=read(c_fd,readBuf,128);
if(n_read==-1){
perror("read");
}else{
printf("get success:%d\n%s\n",n_read,readBuf);
}
}
}
return 0;
}
注:编译成功后要记得手动输入ip和端口号