内容简介:介绍了socket封装的基本流程,并给出程序实例
TCP/IP协议及socket封装
socket编程的基本流程
socket连接的建立(3次握手)
socket连接的断开(3次握手)
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
对应函数接口如图:
socket编程之bind函数
1 |
int bind(int sockfd, const struct sockaddr *addr,socklen_t *addrlen); |
功能描述:
当用socket()函数创建套接字以后,套接字在名称空间(网络地址族)中存在,但没有任何地址给它赋值。bind()把用addr指定的地址赋值给用文件描述符代表的套接字sockfd。addrlen指定了以addr所指向的地址结构体的字节长度。一般来说,该操作称为“给套接字命名”。
通常,在一个SOCK_STREAM套接字接收连接之前,必须通过bind()函数用本地地址为套接字命名。
备注:
调用bind()函数之后,为socket()函数创建的套接字关联一个相应地址,发送到这个地址的数据可以通过该套接字读取与使用。
备注:
bind()函数并不是总是需要调用的,只有用户进程想与一个具体的地址或端口相关联的时候才需要调用这个函数。如果用户进程没有这个需要,那么程序可以依赖内核的自动的选址机制来完成自动地址选择,而不需要调用bind()函数,同时也避免不必要的复杂度。在一般情况下,对于服务器进程问题需要调用bind()函数,对于客户进程则不需要调用bind()函数。
socket编程之accept函数
1 |
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen); |
功能参数描述
accept()系统调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符。新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。
备注:
新建立的套接字准备发送send()和接收数据recv()。
参数:
sockfd, 利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接;
服务器代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/shm.h> #define QUEUE 20 #define MYPORT 8887 #define BUFF_SIZE 1024 int main(int argc, char *argv[]) { int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // 定义socket fd // 定义sockaddr_in struct sockaddr_in server_sockaddr; server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(MYPORT); // host to network short server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);// host to network long // bind socket address to socket fd if (bind(server_sockfd, (struct sockaddr*)&server_sockaddr, sizeof(server_sockaddr)) == -1) { perror("bind"); exit(1); } if (listen(server_sockfd, QUEUE) == -1) { perror("listen"); exit(2); } // 客户端套接字 char buff[BUFF_SIZE]; struct sockaddr_in client_addr; socklen_t length = sizeof(client_addr); // 监听并返回客户端fd int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length); if (conn < 0) { perror("accept"); exit(3); } while (1) { memset(buff, 0, sizeof(buff)); int len = recv(conn, buff, sizeof(buff), 0); if (strcmp(buff, "exit\n") == 0) break; printf("server received:%s", buff); send(conn, buff, len, 0); } close(conn); close(server_sockfd); return 0; } |
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #define MYPORT 8887 #define BUFF_SIZE 1024 int main() { int sock_client_fd = socket(AF_INET, SOCK_STREAM, 0); // 定义server socket struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(0)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器ip // 连接服务器 if (connect(sock_client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("connect"); exit(1); } char sendbuff[BUFF_SIZE], recvbuff[BUFF_SIZE]; while (fgets(sendbuff, sizeof(sendbuff), stdin) != NULL){ send(sock_client_fd, sendbuff, strlen(sendbuff), 0); // 发送 if (strcmp(sendbuff, "exit\n") == 0) break; recv(sock_client_fd, recvbuff, sizeof(recvbuff), 0); printf("client received:%s", recvbuff); memset(recvbuff, 0, sizeof(recvbuff)); memset(sendbuff, 0, sizeof(sendbuff)); } close(sock_client_fd); return 0; } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 编程范式 —— 函数式编程入门
- 【go网络编程】-HTTP编程
- 【go网络编程】-Socket编程
- c++并发编程—分布式编程
- Scala面向对象编程之Trait高级编程技术实践-JVM生态编程语言实战
- 函数式编程之数组的函数式编程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
电子邮件营销密码
[美] Jeanniey Mullen、David Daniesl / 薛剑韬 / 人民邮电出版社 / 2009-9 / 39.00元
在当今互联网蓬勃发展的形势下,电子邮件是互联网应用最广的服务之一。那么如何利用其作为有效的营销工具呢?本书系统地讲解了美国电子邮件营销的预算统筹、营销策略、管理模式、执行机制、涉及的技术、营销实施的细节等,其方法有很强的可循性,并可预见将获得的成果。阅读本书之后,读者会深刻感受到电子邮件营销的博大精深,它既是一门扎实严谨的科学,又是一项充满创造力的艺术。. 本书适合企业管理人员及市场营销人员......一起来看看 《电子邮件营销密码》 这本书的介绍吧!