Socket 编程
来源:互联网 发布:淘宝确认收货 花呗 编辑:程序博客网 时间:2024/06/15 20:58
1 网络进程之间的通信
1.1 本地进程通信
- 消息传递(管道,消息队列)
- 同步(互斥,读写锁)
- 共享内存
1.2 网络进程通信
网络之间如何通信,首先要解决的是如何标识一个唯一的进程,本地进程可以用PID来标识,但这种方式没有办法应用在网络通信中。tcp/ip协议已经帮我们解决了这个问题,协议中的 ip层可以识别唯一主机,而传输层中的“协议+端口”可以识别唯一的应用程序(进程)。也就是说利用(ip,协议,端口)可以标识进程。
2 什么是socket
socket 起源于unix系统,unix系统有一个基本的哲学概念——一切皆文件,也就是说一切东西可以按照文件模式“打开—读、写—关闭”进行操作。即可以把socket视为一种特殊的文件进行操作。
3 socket 基本操作
3.1基本流程
3.2 socket()函数
int socket(int domain , int type , int protocol)
socket()函数用于创建一个socket描述字,用来唯一标识一个socket。把socket视为一种特殊的文件的话,那么socket()相当于创建文件描述字,用作后续对文件进行读写操作的参数。
socket的三个参数
- domain 协议域,常用的有 AF_INET(和ipv4对应) ,AF_INET6(和ipv6对应)
- type socket类型。常用的有,SOCK_STREAM和SOCK_DGRAM
- protocol 协议 常用的有IPPROTO_TCP、IPPTOTO_UDP分别对应 tcp 和udp
3.3 bind()函数
int bind(int socket_fd , const struct sockaddr *addr , socklen_t addrlen )
三个参数
- socket_fd socket描述字,bind()用于将socket()函数创建的描述字绑定一个名字
- addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同
ipv4对应的是:
struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */};
/* Internet address. */struct in_addr { uint32_t s_addr; /* address in network byte order */};
ipv6对应的是:
struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* port number */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */ };
struct in6_addr { unsigned char s6_addr[16]; /* IPv6 address */ };
- addrlen:对应的是地址的长度。
3.4 listen() 、connect()函数
作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
int listen(int sockfd, int backlog);int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- listen函数的第一个参数即为要监听的socket描述字,
- 第二个参数为相应socket可以排队的最大连接个数。
socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
- connect函数的第一个参数即为客户端的socket描述字,
- 第二参数为服务器的socket地址,
- 第三个参数为socket地址的长度。
客户端通过调用connect函数来建立与TCP服务器的连接。
3.5 accept()函数
客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 第一个参数为服务器的socket描述字,
- 第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址
- 第三个参数为协议地址的长度。
如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
3.6 read() 、write()函数
现在可以对文件(socket)进行I/O操作了,常用的函数有:
- read() 、 write()
- recv()、send() 用于tcp
- recvfrom()、sendto() 用于udp
3.7 close()函数
关闭套接字
int close(int fd)
close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。
注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。
4 简单实例
server.cpp 只是简单的demo
#include <cstdio>#include <iostream>#include <cstring>#include <cstdlib>#include <iostream>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#define BACKLOG 10 using namespace std ;int main(int argc , char **argv){ int serv_fd , client_fd ; struct sockaddr_in servaddr , clientaddr ; serv_fd = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP) ; memset(&servaddr , 0 , sizeof(servaddr)) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons(10000) ; servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; bind(serv_fd , (struct sockaddr *) &servaddr , sizeof(servaddr) ) ; listen(serv_fd , BACKLOG) ; while(1) { client_fd = accept(serv_fd , (struct sockaddr *) NULL , NULL) ; //while(1) //{ char recv[40] , send_word[40] ; read(client_fd , recv , sizeof(recv) - 1 ) ; cout << recv << endl ; cin >> send_word ; write(client_fd , send_word , sizeof(send_word)) ; //} close(client_fd) ; } close(serv_fd) ; return 0 ;}
client.cpp demo
#include <iostream>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <arpa/inet.h>#define BACKLOG 10using namespace std ;int main(int argc , char **argv){ int client_fd ; struct sockaddr_in servaddr , clientaddr ; if(argc != 2) { cout << "input error, usage: ./client ip" <<endl ; exit(0) ; } client_fd = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP) ; in_addr_t server_ip = inet_addr(argv[1]) ; memset(&clientaddr , 0 , sizeof(clientaddr) ) ; clientaddr.sin_family = AF_INET ; clientaddr.sin_port = htons(10001) ; clientaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; bind(client_fd , (struct sockaddr *)&clientaddr , sizeof(sockaddr) ) ; memset(&servaddr , 0 , sizeof(servaddr)) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons(10000) ; servaddr.sin_addr.s_addr = server_ip ; connect(client_fd , (struct sockaddr *)&servaddr , sizeof(servaddr)) ; // while(1) //{ char buffer[40] , send_word[40] ; cin >> send_word ; write(client_fd , send_word , sizeof(send_word)) ; read(client_fd , buffer , sizeof(buffer) - 1) ; cout << buffer << endl ; //} close(client_fd) ; return 0 ;}
- socket编程--socket基本概念
- socket编程--socket基本概念
- socket编程
- socket编程
- Socket 编程
- socket编程
- Socket编程
- Socket编程
- Socket编程
- Socket编程
- SOCKET编程
- socket编程
- Socket编程
- socket编程
- Socket 编程
- Socket 编程
- socket 编程
- socket编程
- 二分法的代码实现
- HYSBZ3196-Tyvj 1730 二逼平衡树
- Java 里如何实现线程间通信
- IOS中UITextField和UILabel简单使用
- 第十四课、 C作用域
- Socket 编程
- 关于韩信点兵的算法以及原理
- HDU 1848 Fibonacci again and again 博弈论-SG函数
- 学习linux的简单介绍
- 用shape画内圆外方,形成一个圆形头像
- [FZUOJ
- Spring黑马笔记入门八
- KMP算法
- 有关二维数组与指针的应用:3个学生各学4门课,计算总平均分,并输出第n个学生成绩。小白撸代码....