1.网络编程概述
支持多机通信,进程间通信是基于一个Linux系统的单机通信
TCP/UDP对比
- TCP面向连接(如打电话要先拨号建立连接);UDP是面向无连接,即发送数据之前不需要建立连接
- TCP提供可靠服务,也就是说TCP连接传数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,不保证可靠交付
- TCP面向字节流,实际上是把数据看成一串无结构的字节流;UDP面向报文,没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(微信电话,实时视频会议等)
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP首部开销小,只有8个字节
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
端口号的作用
- 一台拥有ip地址的主机可以提供许多服务,比如Web服务,FTP服务,SMTP服务等等
- ip地址可以寻址到目的主机但不能找到主机上对应的服务,此时端口号就充当主机服务的入口的角色
- 一台主机上有多个端口号来区别不同的服务
- FTP服务的TCP端口号都是21,Telnet服务器的TCP端口号是23,TFTP(简单的文件传输服务)服务器的UDP端口号是69
2.字节序
字节序是指多字节数据在计算机内存中或者网络传输中各字节的存储顺序
小端字节序:低字节存在起始地址
大端字节序:高字节存在起始地址
网络字节序 == 大端字节序
3.网络编程
1.Socket服务器和客户端的开发步骤
2.相应的API用法
int socket(int domain,int type,int protocol);
domain:指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/UDP协议族)
AF_INET IPV4因特网域
AF_INET6 IPV6因特网域
AF_UNIX UNIX域
AF_ROUTE 路由套接字
AF_KEY 密钥套接字
AF_UNSPEC 未指定
type参数指定socket的类型
SOCK_STREAM:
流式套接字提供可靠的,面向连接的通信流,使用TCP协议,保证数据传输的可靠性,顺序性
SOCK_DGRAM:
数据报套接字定义一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并不保证可靠,无差错的,使用数据报协议是UDP
SOCK_RAM:
允许程序中的底层协议,原始套接字允许对底层协议如:IP或ICMP进行直接访问,功能强大,使用方便,一般用于协议的开发
protocol:
通常赋值“0”
0选择type类型对应的默认协议
IPPROTO_TCP TCP协议
IPPROTO_UDP UDP协议
IPPROTO_SCTP SCTP协议
IPPROTO_TIPC TIPC协议
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
sockfd:是一个socket描述符
*addr:主要包含本机IP及端口号信息
IPV4对应的是:
struct sockaddr_in{
as_family_t sin_family;//协议族
in_port_t sin_port;//端口号
struct in_addr sin_addr;//IP地址结构体
unsigned char sin_zero[8];//填充 没有实际意义,为了跟sockaddr结在内存中对齐,这样两者才能相互转换
};
addrlen:结构体长度
IP地址转换API
int inet_aton(const char* straddr,struct in_addr *addr);
把字符串形式的“192.168.1.123”转为网络能识别的格式
char *inet_ntoa(struct in_addr addr);
把网络格式的ip地址转为字符串形式
uin16_t htons(uint16_t host16bitvalue);
返回网络字节序的值
int listen(int sockfd,int backlog);
backlog指定在请求队列中允许的最大请求数
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
addr:客户端的地址,不关心传NULL
addrlen:客户端地址长度
ssize_t write(int fd,const void *buf,size_t nbytes);
ssize_t read(int fd,void *buf,size_t nbytes);
ssize_t send(int sockfd,const void *buf,size_t nbytes,int flags//一般为0);
ssize_t recv(int sockfd,void *buf,size_t nbytes,int flags);
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
addr:服务器的IP地址和端口号的结构体
addrlen:sizeof(struct sockaddr)
3.两进程通信
客户端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <sys/socket.h>
int main(int argc,char **argv)
{
if(argc != 3){
printf("parram is error!\n");
exit(-1);
}
int ret;
int c_fd;
struct sockaddr_in c_fd;
int n_read;
char r_buf[128] = {0};
char w_buf[128] = {0};
memset(&c_addr,0,sizeof(struct sockaddr_in));
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);
socklen_t len = sizeof(struct sockaddr_in);
ret = connect(c_fd,(struct sockaddr *)&c_addr,len);
if(ret == -1){
perror("connect");
exit(-1);
}
printf("connect to %s\n",inet_ntoa(c_addr.sin_addr));
while(1){
if(fork() == 0){
printf("input message:");
memset(w_buf,0,128);
fgets(w_buf,128,stdin);//等待键盘输入
write(c_fd,w_buf,128);
}
n_read = read(c_fd,r_buf,128);
if(n_read == -1){
perror("read");
}
else{
printf("message from server:%s\n",r_buf);
}
}
return 0;
}
服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <arpa/inet.h>
int main(int argc,char **argv)
{
if(argc != 3){
printf("parram is error!\n");
exit(-1);
}
int s_fd;
int c_fd;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
int n_read;
char r_buf[128] = {0};
char w_buf[128] = {0};
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
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);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
while(1){
listen(s_fd,10);
socklen_t len = sizeof(struct sockaddr_in);
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);
if(c_fd){
perror("accept");
exit(-1);
}
printf("%s connected\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0){
if(fork() == 0){
while(1){
printf("input message:");
memset(w_buf,0,128);
fgets(w_buf,128,stdin);
write(c_fd,w_buf,128);
}
}
while(1){
n_read = read(c_fd,r_buf,128);
if(n_read == -1){
perror("read")
}else{
printf("message from client:%s\n",r_buf);
}
}
}
}
return 0;
}