Linux_networking_programing(Linux网络编程总结)

来源:互联网 发布:数据分析系统 编辑:程序博客网 时间:2024/06/05 21:03

自我总结之Linux网络编程。

前言:

网络:TCP/IP模型:物理层、数据链路层、网络层、传输层
网络数据传输:以太网帧、IP报文、TCP/UDP报文

一、进程间通信(IPC):

匿名管道,命名管道,socketpair,信号,信号量,锁,文件锁,共享内存等

原理:在进程外的公共区域申请内存,然后双方通过某种方式去访问公共区域内存

分类:

1、小数据量通信:管道,socketpair

2、大数据量通信:共享内存

3、进程间同步:socketpair、管道、锁、文件锁、信号量

(一)匿名管道:

内核buffer大小(ubuntu64k),满后write阻塞,

read时,管道没有数据,阻塞等待。
read时,write段已经关闭,管道有数据就读,没有返回0表示结束
1、创建:pipe产生两个文件描述符表示管道两端(读写);
2、读写:read,有数据就读;无数据写端关闭,返回0;写端未关闭,阻塞
write:如果管道有空间,写数据,长度以来管道buffer的剩余空间,返回值为写入的长度
如果管道无空间,那么阻塞;
如果read端已关闭,那么产生一个SIGPIPE信号,程序终止。如果程序处理了SIGPIPE,
那么程序不会终止,write返回-1,错误码标记为EPIPE;
3、应用:单工:单方通信;半双工:两个方向通信,同一时刻只能有一个方向通信; 全双工:同时两方通信

(二)命名管道:

可用于非亲缘关系的进程;

创建:mkfifo
打开读端:open(“管道文件名”, O_RDONLY); 如果此时没有其他进程打开写端,那么该open阻塞;
打开写端:open(“管道文件名”, O_WRONLY);

(三)socketpair:

和匿名管道类似,不过是全双工

创建:int fd[2];
  socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
(四)mmap时间共享内存
有亲缘关系的进程mmap共享:匿名映射;
无亲缘关系的进程mmap共享:内存文件;
使用shm_open打开共享内存文件,以/起头,中间不能有/
(五)文件锁
int fd = open("a");
ret = flock(fd, LOCK_SH|LOCK_NB);
flock(fd, LOCK_UN);

int fd = open("a");
flock(fd, LOCK_SH);
flock(fd, LOCK_UN);

int fd = open("a");
flock(fd, LOCK_EX);
flock(fd, LOCK_UN);
(六)锁:pthread_mutex_init


二、TCP套接字通信(TCP/IP协议):

基于流的面向连接的通信.

流程:服务器:创建socket,绑定地址bind,监听listen;客户端:创建socket,发送链接请求connect
  接收连接请求accept发送数据send
  接收数据recv
代码:server:
int main(){int fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = INADDR_ANY;bind(fd, (struct sockaddr*)&addr, sizeof(addr));listen(fd, 10);int newfd = accept(fd, NULL, NULL);char buf[1024];recv(newfd, buf, sizeof(buf), 0);printf("recv data:%s\n", buf);send(newfd, buf, strlen(buf)+1, 0);close(newfd);close(fd);}client:int main(){int fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = inet_addr("127.0.0.1");connect(fd, (struct sockaddr*)addr, sizeof(addr));send(fd, "hello", 6, 0);char buf[1024];recv(fd, buf, sizeof(buf), 0);return 0;}

套接字描述符:使用 int shutdown(int sockfd, int how); 关闭一个方向的通信
网络字节序:大端字节序

设置套接字选项:fcntl/
int len = 256;setsockopt(sockfd, SOL_SOCKET,SO_RCVBUF,&len, sizeof(len));

关闭套接字:close,对端关闭,read/recv返回0,本端写,产生SIGPIPE,若忽略SIGPIPE,那么写返回-1,错误码EPIPE;

三、UDP套接字:基于报文的通信

创建socket: int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
绑定地址:同TCP
发送和接收: sendto, 如果UDP调用了connect,也可以使用send
广播和多播:
关闭socket:close
UDP的数据是基于报文的,客户端调用一次send,产生一个UDP报文,接收一次只能接收一个报文
MTU(1400);

四、通信服务模型:
使用多进程:每个客户端对应一个进程,资源消耗大(早期apache服务器)
使用多线程:每个客户端对应一个线程,资源消耗大(优化过的Apache)
&&多路IO复用技术:iocp(windows)
1、select(跨平台):在少量文件描述符集合中,效率高,只能监听最多1024文件描述符
2、epoll(linux):支持大规模网络服务,只支持linux
使用多路IO复用技术和线程池:两个线程,一个负责epoll_wait和accept,另外一个线程负责接收和处理数据;
支持大规模网络服务,并且支持高并发;
使用多进程并发和多路IO复用技术:多个进程同事监听一个端口,如果外部有链接,多个进程通过内核实现的竞争机制会有一个进程被唤醒
效率非常高,Nginx就是用这种方式
#libevent:
event_base:
evconnlistener:对应一个坚挺的服务器
event


流程:创建一个集合->往集合增加各种事件->给时间一些任务(监听或者读写任务)->给时间设定回调函数(当任务完成时,event可以通过回调函数通知上层)
while(1) //监听event_base,看哪个有事件
code:
void conn_eventcb(struct bufferevent*bev,short events, void * user_data){if(events & BEV_EVENT_EOF)else if(events & BEV_EVENT_ERROR)bufferevent_free(bev);}void conn_writecb(struct bufferevent*bev, void *user_data){struct evbuffer*output = bufferevent_get_output(bev);if(evbuffer_get_length(output) == 0) bufferevent_free(bev);}void listener_cb(struct evconnlistener*l, evutil_socket_t sock,//文件描述符struct sockaddr*addr, int socklen, void *ptr)){struct event_base*base = ptr;struct bufferevent*bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);if(bev == NULL)exit(0);buffervnt_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);bufferevent_enble(bev, EV_WRITE);bufferevent_disable(bev, EV_READ);bufferevent_write(bev, "hello", 5); //异步IO}int main(){struct event_base* base = event_base_new();if(base == NULL)return 0;struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8899);addr.sin_addr.s_addr = INADDRY_ANY;struct evconnlistener *listener = evconnlistener_new_bind(base,listener_cb(callback),(void*)base(callback argument),LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE(opt),-1, (struct sockaddr*)&addr(listen addr), sizeof(addr));if(listener == NULL) return 0;event_base_dispatch(base); return 0;}


五、HTTP协议
通信模型:支持客户端/服务器模式,简单快速,灵活,短连接,无状态
HTTP服务器/web服务器:apache,nginx,iis(windows)
客户端:浏览器
curl命令:
HTTP请求:请求行,消息报头,请求正文
HTTP响应:状态行,消息报头,响应正文
&&libcurl:基本流程:初始化CURL环境,创建CURL对象,设置CURL,执行CURL

bool getUrl(char *filename){CURL *curl;CURLcode res;FILE* fp;if((fp = fopen(filename, "w")) == NULL)return false;struct curl_slist *headers = NULL;headers = curl_slist_append(headers, "Accept: Agent-007");curl = curl_easy_init();if(curl){curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:9999");curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp);res = curl_easy_perform(curl);if(res != 0){curl_slist_free_all(headers);curl_easy_cleanup(curl);}fclose(fp);return true;}}ssize_t curl_callback(char* data, int m, int n, void* ptr){    // "abc def"    // string str = data; // OK???  NO    string& ret = *(string*)ptr;    string str;    std::copy(data, data+m*n, back_inserter(str));    ret += str;    return m*n;}bool postUrl(char *filename){CURL *curl;char* res = "curl test";curl = curl_easy_init();if(curl){curl_easy_setopt(curl,CURLOPT_POSTFIELDS, res);curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);//sslcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);CURLcode code = curl_easy_perform(curl);curl_easy_cleanup(curl);}}




原创粉丝点击