零、 IP地址
IPv4 4字节地址簇
IPv6 16字节地址簇
IPv4标准的4字节IP地址分为网络地址和主机地址,分成A/B/C/D/E等类型。
A类地址的首字节范围:0-127
B类地址的首字节范围:128-191
C类地址的首字节范围:192-223
另一种表达方法:
A类地址的首位以0开始
B类地址的前2位以10开始
C类地址的前3位以110开始
一、 理解下TCP和UDP
根据数据传输方式的不同,基于网络协议的套接字一般分成TCP套接字和UDP套接字。
TCP套接字是面向连接的,又称为基于流Stream的套接字,TCP(Transmission Control Protocol 传输控制协议)的简写,书中将TCP/IP协议栈分成4层架构,掌握这4层协议栈就足够了。另外不同于OSI 7层架构:物理层-->数据链路层-->网络层-->传输层-->会话层-->表示层-->应用层。
1. 链路层:是物理链接领域标准化的结果,也是最基本的领域,专门定义LAN,WAN,MAN等网络标准。
2. IP层:复杂网络中,负责路径的选择。IP本身是面向消息的,不可靠的协议。
3. TCP/UDP层:已IP层提供的路劲信息为基础完成实际的数据传输,因此也称为传输层。TCP比UDP复杂,TCP可以保证可靠的数据传输。
4. 应用层:根据程序特点决定服务器端和客户端之间数据传输规则。
二、 实现基于TCP的服务器端和客户端
1. TCP服务器端的默认函数调用顺序
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
成功时返回文件描述符,失败时返回-1.
domain 套接字中使用的协议簇信息;
type 套接字数据传输类型信息;
protocol 计算机间通信使用的协议信息。
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
成功时返回0,失败时返回-1
sockfd 要分配地址信息的套接字文件描述符
myaddr 存有地址信息的结构体变量地址值
addrlen 第二个结构体变量的长度
#include <sys/socket.h>
int listen(int sock, int backlog);
成功时返回0,失败时返回-1
sock 希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数成为服务器端套接字
backlog 连接请求等待队列长度,若为5,则队列长度为5,表示最多5个连接请求进入队列。
#include <sys/socket.h>
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
成功时返回创建的套接字文件描述符,失败时返回-1
sock 服务器套接字的文件描述符
addr保存发起连接请求的客户端地址信息的变量地址值,函数调用后传递来的地址变量参数填充客户端地址信息
addrlen 第二个参数addr结构体的长度
#include <sys/socket.h>
int connect (int sock, struct sockaddr *servaddr, socklen_t addrlen);
成功时返回0,失败时返回-1
sock 客户端套接字文件描述符
servaddr 保存目标服务器端地址信息的变量地址值
addrlen 以字节为单位传递已传递给第二个结构体参数servaddr的地址变量长度
![4.1 TCP的服务器端/客户端1 4.1 TCP的服务器端/客户端1](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwybHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEx6SXdNVGN3TVRFNE1UWXlNalUxT0RVMlAzZGhkR1Z5YldGeWF5OHlMM1JsZUhRdllVaFNNR05FYjNaTU1rcHpZakpqZFZrelRtdGlhVFYxV2xoUmRtUXlWblZrTWxaMVRWUkZlRTFVUlhndlptOXVkQzgxWVRaTU5Vd3lWQzltYjI1MGMybDZaUzgwTURBdlptbHNiQzlKTUVwQ1VXdEdRMDFCUFQwdlpHbHpjMjlzZG1Vdk56QXZaM0poZG1sMGVTOURaVzUwWlhJPQ%3D%3D.jpg?w=700)
三、迭代回声服务器端、客户端
服务器端在同一时刻只与一个客户端相连,并提供回声服务;
服务器端依次向5个客户端提供服务并退出
客户端接收用户输入的字符串并发送给服务器
服务器端将接收到的字符串传回客户端
服务器与客户端之间的字符串回声一直到执行到客户端输入Q为止。
Server代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]){
int serv_sock;
int clnt_sock;
char message[BUF_SIZE];
int str_len,i;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size;
if(argc != 2){
printf("Usage : %s <port>\n",argv[0]);
exit(1);
}
serv_sock = socket(PF_INET,SOCK_STREAM,0);
if(serv_sock == -1){
error_handling("socket() error");
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1){
error_handling("bind() error");
}
if(listen(serv_sock,5) == -1){
error_handling("listen() error");
}
clnt_addr_size = sizeof(clnt_addr);
for(i=0;i<5;i++){
clnt_sock = accept(serv_sock,(struct sockaddr *)&clnt_addr,&clnt_addr_size);
if(clnt_sock == -1){
error_handling("accept() error");
}else{
printf("Connected client %d\n",i+1);
}
while((str_len = read(clnt_sock,message,BUF_SIZE)) != 0)
{
write(clnt_sock,message,str_len);
printf("client %d:message %s",i+1,message);
}
close(clnt_sock);
}
close(serv_sock);
return 0;
}
void error_handling(char *message){
fputs(message,stderr);
fputs("\n",stderr);
exit(1);
}
Client代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE1024
void error_handling(char *message);
int main(int argc,char *argv[]){
int sock;
struct sockaddr_in serv_addr;
char message[BUF_SIZE];
int str_len;
if(argc != 3){
printf("Usage : %s <IP> <port>\n",argv[0]);
exit(1);
}
sock = socket(PF_INET,SOCK_STREAM,0);
if(sock == -1){
error_handling("socket() error");
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if(connect(sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
error_handling("connect() error\r\n");
}else{
printf("Connected....");
}
while(1){
printf("Input message(Q to quit):");
fgets(message,BUF_SIZE,stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
write(sock,message,strlen(message));
str_len = read(sock,message,BUF_SIZE-1);
message[str_len] = 0;
printf("Message from server : %s \n",message);
}
close(sock);
return 0;
}
void error_handling(char *message){
fputs(message,stderr);
fputs("\n",stderr);
exit(1);
}
alex@alex-VirtualBox:~/Share/Test/tcpip$ ./echo_client 127.0.0.1 9190
Connected....Input message(Q to quit):hello
Message from server : hello
Input message(Q to quit):what
Message from server : what
Input message(Q to quit):who
Message from server : who
Input message(Q to quit):
alex@alex-VirtualBox:~/Share/Test/tcpip$ ./echo_server 9190
Connected client 1
client 1:message hello
lient 1:message what
lient 1:message who