1. IP地址(IPV4 IPV6)
以一个32位的整形表示:
172.166.111.110 -》点分10进程
地址
255.255.255.255
表示为 FF FF FF FF ->二进程
2.IP地址分类
A类地址:0.0.0.0 -- 127.255.255.255
网络号 + 主机号 网络号高(0-7) 主机号低(8—31)
B类地址:128.0.0.0 -- 191.255.255.255 网络号高(0-15) 主机号低(16-31)
C类地址: 192.0.0.0 -- 223.255.255.255 网络号高(0-23) 主机号低(24-31)
D类地址:224.0.0.0 -- 239.255.255.255 用来做组播网络
E类地址:240.0.0.0 -- 255.255.255.255 用来做广播网络
说明:
网络号 -》识别是那个网络
主机号 -》识别是那一台PC
192.168.7.6 ---》 C类地址
网络通信时必须要地址段相同
192.168.6.6 ---》 C类地址
3.端口号 -》识别主机中的哪一个进程
IP地址:识别网络中的那一套主机,端口号就是用来识别,当前主机中的哪一个进程
端口号的取值范围:1-65535
在使用端口号时要注意:一般使用1000以后的端口号,因为1000以前的端口号,一般被系统进程占用着
-----------------------------------------------------------------------------------------------------
传输层协议:
TCP协议 UDP协议
TCP协议可靠传输协议:一般用于文件传输,与控制命令传输。
UDP协议不可传输协议:一般用于多媒体体数据传输,例如
音频,视屏
TCP协议的搭建流程:
-----------------------------客户端-----------------------------------
1.创建socket
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int socket(int domain, int type, int protocol);
参数一:IP协议 AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
参数二:传输协议
SOCK_STREAM ---》TCP协议
SOCK_DGRAM ---》UDP协议
参数三:socket的属性 填写为0 默认属性
返回值:成功发回 新的socket文件描述符 ,
失败返回 -1
2.链接服务器 connect (难点!!!!!!!!重点!!!)
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数一:socket文件描述符
参数二:服务器信息结构体
参数三:服务器信息结构体的大小
返回值:链接成功返回0 链接失败返回-1
const struct sockaddr *addr 服务器信息结构体 他的所在路径为 /usr/include/linux/in.h
struct sockaddr 与 struct sockaddr_in 在使用上是等价的。
struct sockaddr_in结构体介绍:
struct sockaddr_in {
__kernel_sa_family_t
sin_family;
/* Address family协议族 IPV4 还是IPV6协议*/
__be16
sin_port;
/* Port number端口号*/
struct in_addr
sin_addr;
/* Internet addressIP地址*/
}
/* Internet address. */IP地址结构体
struct in_addr {
__be32
s_addr;
};
IP地址转换函数:
#include <sys/socket.h>
#include <netinet/in.h> -》会与linux/in.h冲突,所以在加入点分10进制转换函数后要把原来那个头文件去掉
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp); -》点分10进制转整形
char *inet_ntoa(struct in_addr in); -》整形转点分10进制类型
大小端格式:在网络通信中都使用大端格式进行通信(所以我们需要转换端口号)
大端格式:低地址存储高位字节
小段格式:低地址存储低位字节
uint16_t htons(uint16_t hostshort); -》主机序转网络序
uint16_t ntohs(uint16_t netshort); -》网络序转主机序
--------------------------------服务器端----------------------------------------
1.创建socket
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int socket(int domain, int type, int protocol);
参数一:IP协议 AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
参数二:传输协议 SOCK_STREAM ->TCP协议
SOCK_DGRAM -》UDP协议
参数三:socket的属性 填写为0 默认属性
返回值:成功发回 新的socket文件描述符 ,
失败返回 -1
2.绑定socket
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数一:创建的socket文件描述符
参数二:服务器绑定信息
参数三:服务器信息结构体的大小
返回值:成功返回0 ,失败返回-1
3.设置为监听socket
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int listen(int sockfd, int backlog);
参数一:创建的socket文件描述符
参数二:最大监听数 (同时可以接受多少个客户端的链接请求)
返回值:成功返回0 失败返回-1.
4.链接服务器 (重点!!!) 他会阻塞等待客户端链接过来
头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数一:监听的文件描述符
参数二:客户端的信息结构体(例如客户端的IP,端口号)
参数三:成功接受客户端的信息结构体大小
返回值:接受链接请求成功,返回一个新的文件描述符,失败返回-1
--------------------------------------------------------------------------------------------------------------------------------------
练习:tcp服务器和客户端的简单通信实现
【server.c】
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
//写操作
void *write_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{
scanf("%s",buf);
write(fd,buf,strlen(buf));
}
}
//读操作
void *read_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{
bzero(buf,50);
read(fd,buf,50);
printf("buf=%s\n",buf);
}
}
int main(int argv,char **argc)
{
if(argv<3)
{
perror("plese input ./server prot ip");
return 0;
}
//1.创建TCP socket
int sockfd=socket( AF_INET,SOCK_STREAM ,0);
if(sockfd<0)
{
perror("create sock fail\n");
}
else
{
printf("create sock %d\n",sockfd);
}
//设置服务器绑定信息
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET ; //IPV4协议
serveraddr.sin_port = htons(atoi(argc[1])); //端口号
serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址 "0.0.0.0" ->万用地址
// htonl(INADDR_ANY) //INADDR_ANY ->万用IP宏
//2.绑定服务器
int ret=bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
if(ret != 0)
{
perror("bind fail\n");
}
else
{
printf("bind ok\n");
}
//3.设置为监听socket
ret=listen(sockfd,5);
if(ret != 0)
{
perror("listen fail\n");
}
else
{
printf("listen ok\n");
}
//定义一个结构体保存客户端的信息
struct sockaddr_in clienaddr;
bzero(&clienaddr,sizeof(clienaddr));
//定义一个整形保存接收的长度
socklen_t len=sizeof(clienaddr);
//4.接收客户端的链接请求(重点!!!)
while(1)
{
int newfd=accept(sockfd,(struct sockaddr *)&clienaddr,&len);
if(newfd>0)
{
printf("accept OK fd=%d\n",newfd);
printf("clien ip=%s,port=%d\n",inet_ntoa(clienaddr.sin_addr),ntohs(clienaddr.sin_port));
//写入信息携程
pthread_t pid;
pthread_create(&pid,NULL,write_fun,(void *)&newfd);
//读取信息线程
pthread_t pid1;
pthread_create(&pid1,NULL,read_fun,(void *)&newfd);
}
else
{
perror("accept fail\n");
}
}
}
----------------------------------------------------------------------------------------------------------------------------------------------
【client.c】
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *write_fun(void *arg)
{
int fd=*(int *)arg;
char buf[50]={0};
//输入指令
while(1)
{
scanf("%s",buf);
write(fd,buf,strlen(buf));
}
}
int main(int argv,char **argc)
{
if(argv<3)
{
perror("plese input ./clien prot ip");
return 0;
}
//创建TCP socket
int sockfd=socket( AF_INET,SOCK_STREAM ,0);
if(sockfd<0)
{
perror("create sock fail\n");
}
else
{
printf("create sock %d\n",sockfd);
}
//设置服务器信息
struct sockaddr_in serveraddr;
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET ; //IPV4协议
serveraddr.sin_port = htons(atoi(argc[1])); //端口号
serveraddr.sin_addr.s_addr = inet_addr(argc[2]);//IP地址
//进行读写操作
char buf[50]={0};
//链接服务器
int ret=connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
if(ret != 0)
{
perror("connect fail\n");
}
else
{
//使用一个写入线程
pthread_t pid;
pthread_create(&pid,NULL,write_fun,(void *)&sockfd);
while(1)
{
bzero(buf,sizeof(buf));
ret=read(sockfd,buf,sizeof(buf));
if(ret>0)
{
printf("buf=%s\n",buf);
}
else
{
perror("read fail\n");
return 0;
}
}
}
//写一个简单的聊天客户端 可以进行读写操作
}
-----------------------------------------------------------------------------------------------------------
程序运行时必须
先运行服务器程序,再运行客户端程序,并且设置端口和服务器ip地址