国家或全球ISP
移动网络
本地ISP
家庭网络
路由器是跨网段的,交换机是同一个网段的
hub是扩展节点,与其他都连接上。
C类局域网,只有0~254个端口可以使用,容易打架。
解决第一个问题就牵扯到第二层的网络包格式。对于以太网,第二层的最开始,就是目标的MAC地址和源的MAC地址。
学完本节课程后,同学将掌握UDP协议和TCP协议的基本概念、特点和使用常见,掌握TCP协议中的流量控制、丢包问题和拥塞问题,掌握编写简单服务器/客户端程序的的基础知识
UDP(User Datagram Protocol:用户数据报协议)
UDP相对于TCP来说,是一个非常简单的协议
首先要先建立一个连接,所以我们先来看连接维护问题。
TCP的连接建立,我们常常称为三次握手。
如果是两次的话,只能确定A说的B能听到,但是B不能确定B说的A听到了吗。
#include
int main(){
int a = 321;
char *p = (char *)&a;
printf("addr = %p, data = %#x\n", p, *p);
printf("addr = %p, data = %#x\n", p + 1, *(p + 1));
printf("addr = %p, data = %#x\n", p + 2, p[2]);
printf("addr = %p, data = %#x\n", p + 3, p[3]);
return 0;
}
低地址
存储的是低字节
,这就是小端模式;./a.out [0]
addr = 0x7ffff8f0762c, data = 0x41
addr = 0x7ffff8f0762d, data = 0x1
addr = 0x7ffff8f0762e, data = 0
addr = 0x7ffff8f0762f, data = 0
#include
#include
int main(){
int a = 0x12345678;
printf("%#x\n", a);
int b = htonl(a);
printf("%#x\n", b);
/*
int a = 321;
char *p = (char *)&a;
printf("addr = %p, data = %#x\n", p, *p);
printf("addr = %p, data = %#x\n", p + 1, *(p + 1));
printf("addr = %p, data = %#x\n", p + 2, p[2]);
printf("addr = %p, data = %#x\n", p + 3, p[3]);
*/
return 0;
}
@DESKTOP-NA5RGM7 net % ./a.out [0]
0x12345678
0x78563412
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 8000
#define MAXLINE 80
int main() {
struct sockaddr_in serveraddr, cliaddr;
int listenfd, connfd;
socklen_t cliaddr_len;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int n, i;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr, sizeof(serveraddr));
//服务器 ip地址:端口初始化
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, 3);
printf("Accepting connections...\n");
while(1) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddr_len);
printf("received from %s:%d\n",\
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
n = read(connfd, buf, MAXLINE);
for (i = 0; i < n; i++) {
buf[i] = toupper(buf[i]);
}
write(connfd, buf, n);
close(connfd);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 8000
#define MAXLINE 80
int main() {
struct sockaddr_in serveraddr;
char buf[MAXLINE] = {"hello tcp"};
char str[INET_ADDRSTRLEN];
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);
connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
write(sockfd, buf, strlen(buf));
int n = read(sockfd, buf, MAXLINE);
printf("reponse from server:\n");
write(1, buf, n);
putchar(10);
close(sockfd);
return 0;
}
gcc server.c -o server -lpthread
,#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 8000
#define MAXLINE 80
#define prrexit(msg) {\
perror(msg);\
exit(1);\
}
typedef struct Task {
int fd;
struct Task *next;
} Task;
typedef struct Task_pool {
Task *head;
Task *tail;
pthread_mutex_t lock;
pthread_cond_t havetask;
} Task_pool;
Task_pool *task_pool_init() {
Task_pool *tp = (Task_pool *)malloc(sizeof(Task_pool));
tp->head = NULL;
tp->tail = NULL;
pthread_mutex_init(&tp->lock, NULL);
pthread_cond_init(&tp->havetask, NULL);
return tp;
}
void task_pool_push(Task_pool *tp, int fd) {
pthread_mutex_lock(&tp->lock);
Task *t = malloc(sizeof(Task));
t->fd = fd;
t->next = NULL;
if(!tp->tail) {
tp->head = tp->tail = t;
} else {
tp->tail->next = t;
tp->tail = t;
}
pthread_cond_broadcast(&tp->havetask);
pthread_mutex_unlock(&tp->lock);
}
Task task_pool_pop(Task_pool *tp) {
pthread_mutex_lock(&tp->lock);
while(!tp->head) {
pthread_cond_wait(&tp->havetask, &tp->lock);
}
Task tmp, *k;
k = tp->head;
tmp = *k;
tp->head = tp->head->next;
if (!tp->head)
tp->tail = NULL;
free(k);
pthread_mutex_unlock(&tp->lock);
return tmp;
}
void task_pool_free(Task_pool *tp) {
pthread_mutex_lock(&tp->lock);
Task *p = tp->head, *k;
while(p) {
k = p;
p = p->next;
free(k);
}
tp->head = NULL;
pthread_mutex_unlock(&tp->lock);
//pthread_mutex_destory(&tp->lock);
//pthread_cond_destory(&tp->havetask);
free(tp);
return ;
}
void *up_server(void *arg) {
pthread_detach(pthread_self());
char buf[MAXLINE];
int n, i;
Task_pool *tp = arg;
while(1){
Task tmp = task_pool_pop(tp);
int connfd = tmp.fd;
printf("get task fd = %d\n", connfd);
while(1) {
n = read(connfd, buf, MAXLINE);
if (!strncmp(buf, "quit", 4))
break;
write(1, buf, n);
for (i = 0; i < n; i++) {
buf[i] = toupper(buf[i]);
}
write(connfd, buf, n);
}
printf("finish task fd = %d\n", connfd);
close(connfd);
}
return (void *)0;
}
int main() {
struct sockaddr_in serveraddr, cliaddr;
int listenfd, connfd;
socklen_t cliaddr_len;
char str[INET_ADDRSTRLEN];
int i;
Task_pool *tp = task_pool_init();
/**多线程逻辑实现
*
*/
pthread_t tid;
for (i = 0; i < 4; i++) {
pthread_create(&tid, NULL,up_server,(void *)tp);
printf("new thread is %#lx\n", tid);
}
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0)
prrexit("socket");
bzero(&serveraddr, sizeof(serveraddr));
//服务器 ip地址:端口初始化
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) {
prrexit("bind");
}
if(listen(listenfd, 3))
prrexit("listen")
printf("Accepting connections...\n");
while(1) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddr_len);
if (connfd < 0)
prrexit("accept");
printf("received from %s:%d\n",\
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
/**多进程逻辑实现
*
pid_t pid = fork();
if (pid < 0)
prrexit("fork");
//父进程:等待 创建链接
if(pid > 0) {
close(connfd);
while(waitpid(-1, NULL, WNOHANG) > 0) {}
continue;
}
close(listenfd);
*/
task_pool_push(tp, connfd);
}
task_pool_free(tp);
return 0;
}
gcc client.c -o client
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 8000
#define MAXLINE 80
int main() {
struct sockaddr_in serveraddr;
char buf[MAXLINE] = {"hello tcp"};
char str[INET_ADDRSTRLEN];
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, "127.0.0.1", &serveraddr.sin_addr);
connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
// write(sockfd, buf, sizeof(buf));
int n;
while (n = read(0, buf, MAXLINE)){
//printf("__LINE__");
write(sockfd, buf, n);
if(!strncmp(buf,"quit",4))
break;
n = read(sockfd, buf, MAXLINE);
printf("reponse from server:\n");
write(1, buf, n);
}
close(sockfd);
return 0;
}
加上epolll轮询机制
,使得不再专门服务某个客户端
;只需要轮询为连接的客户按顺序服务一下。#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 8000
#define MAXLINE 80
#define prrexit(msg) {\
perror(msg);\
exit(1);\
}
typedef struct Task {
int fd;
struct Task *next;
} Task;
typedef struct Task_pool {
Task *head;
Task *tail;
pthread_mutex_t lock;
pthread_cond_t havetask;
} Task_pool;
Task_pool *task_pool_init() {
Task_pool *tp = (Task_pool *)malloc(sizeof(Task_pool));
tp->head = NULL;
tp->tail = NULL;
pthread_mutex_init(&tp->lock, NULL);
pthread_cond_init(&tp->havetask, NULL);
return tp;
}
void task_pool_push(Task_pool *tp, int fd) {
pthread_mutex_lock(&tp->lock);
Task *t = malloc(sizeof(Task));
t->fd = fd;
t->next = NULL;
if(!tp->tail) {
tp->head = tp->tail = t;
} else {
tp->tail->next = t;
tp->tail = t;
}
pthread_cond_broadcast(&tp->havetask);
pthread_mutex_unlock(&tp->lock);
}
Task task_pool_pop(Task_pool *tp) {
pthread_mutex_lock(&tp->lock);
while(!tp->head) {
pthread_cond_wait(&tp->havetask, &tp->lock);
}
Task tmp, *k;
k = tp->head;
tmp = *k;
tp->head = tp->head->next;
if (!tp->head)
tp->tail = NULL;
free(k);
pthread_mutex_unlock(&tp->lock);
return tmp;
}
void task_pool_free(Task_pool *tp) {
pthread_mutex_lock(&tp->lock);
Task *p = tp->head, *k;
while(p) {
k = p;
p = p->next;
free(k);
}
tp->head = NULL;
pthread_mutex_unlock(&tp->lock);
//pthread_mutex_destory(&tp->lock);
//pthread_cond_destory(&tp->havetask);
free(tp);
return ;
}
void *up_server(void *arg) {
pthread_detach(pthread_self());
char buf[MAXLINE];
int n, i;
Task_pool *tp = arg;
while(1){
Task tmp = task_pool_pop(tp);
int connfd = tmp.fd;
printf("get task fd = %d\n", connfd);
if (1) { //注意这里引入epoll之后只需要执行一次
n = read(connfd, buf, MAXLINE);
write(1, buf, n);
for (i = 0; i < n; i++) {
buf[i] = toupper(buf[i]);
}
write(connfd, buf, n);
}
printf("finish task fd = %d\n", connfd);
if (!strncmp(buf, "QUIT", 4))
close(connfd);
}
return (void *)0;
}
int main() {
struct sockaddr_in serveraddr, cliaddr;
int listenfd, connfd;
socklen_t cliaddr_len;
char str[INET_ADDRSTRLEN];
int i;
Task_pool *tp = task_pool_init();
/**多线程逻辑实现
*
*/
pthread_t tid;
for (i = 0; i < 4; i++) {
pthread_create(&tid, NULL,up_server,(void *)tp);
printf("new thread is %#lx\n", tid);
}
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0)
prrexit("socket");
/**
*引入epoll机制
*/
int epfd = epoll_create(256);
struct epoll_event ev, events[256];
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD,listenfd, &ev);
//服务器 ip地址:端口初始化
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) {
prrexit("bind");
}
if(listen(listenfd, 3))
prrexit("listen")
printf("Accepting connections...\n");
while(1) {
int nfds = epoll_wait(epfd, events, 256, -1);
for (i = 0; i < nfds; i++) {
if (events[i].data.fd == listenfd) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddr_len);
if (connfd < 0)
prrexit("accept");
printf("received from %s:%d\n",\
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
} else if (events[i].events & EPOLLIN) {
int clifd = events[i].data.fd;
if (clifd < 3)
continue;
task_pool_push(tp, connfd);
}
}
/**多进程逻辑实现
*
pid_t pid = fork();
if (pid < 0)
prrexit("fork");
//父进程:等待 创建链接
if(pid > 0) {
close(connfd);
while(waitpid(-1, NULL, WNOHANG) > 0) {}
continue;
}
close(listenfd);
*/
}
task_pool_free(tp);
return 0;
}
超文本传输协议(英文:HyperTextTransferProtocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
HTTP/1.1协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源