网络编程——TCP

2024-04-29 15:44
文章标签 tcp 编程 网络

本文主要是介绍网络编程——TCP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

socket

在这里插入图片描述

socket类型

流式套接字(SOCK_STREAM) TCP
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复、无丢失、无失序的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK_DGRAM) UDP
提供无连接服务、不可靠。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)
可以对较低层次协议如IP、ICMP直接访问。

函数接口

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */int socket(int domain, int type, int protocol);
作用:创建一个通信的节点(创建一个socket文件描述符)
参数:domain:AF_UNIX, AF_LOCAL   本地通信(进程的第七种通信)            unix(7)AF_INET             借助ipv4进行通信			          	ip(7)AF_INET6            借助ipv6进行通信          			ipv6(7)type:SOCK_STREAM:用TCP进行通信SOCK_DGRAM:使用UDP进行通信protocol: 0返回值:成功返回一个socket文件描述符失败的话返回-1

TCP的编程流程

在这里插入图片描述
connect

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:客户端的socket连接服务器
参数:sockfd:socket接口返回的文件描述符addr:服务器的地址,帮助文档的接收在bind里,protocol: 0返回值:第二个参数struct sockaddr *addr的解释
struct sockaddr {sa_family_t sa_family;   //同socket接口的domain参数char        sa_data[14];
}上面的接口类型只是socket接口族为了兼容多种协议,定义的一个通用的结构体,实际编程的时候,
需要你根据具体的协议类型,使用具体协议的结构体,对于ipv4来讲,需要看ip的第7个手册(man 7 ip)
就能得到下面这个地址struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* 端口:网络字节序 */struct in_addr sin_addr;   /* IP地址:网络字节序 */
};/* Internet address. */
struct in_addr {uint32_t       s_addr;     /* ip地址:网络字节序 */
};addrlen:地址的长度返回值:0 -1

recv/send

#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收网络的数据
参数:sockfd:文件描述符buf:数据的存放缓冲区len:buf缓冲区的最大长度flags:默认填0 阻塞接收
返回值:成功会返回实际接收到的字节个数失败返回-1如果返回0的话,代表对端退出ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:发送网络的数据
参数:sockfd:文件描述符buf:数据的发送缓冲区len:发的缓冲区大小flags:默认填0返回值:成功会返回实际发送成功的字节个数失败返回-1

bind

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:绑定服务器地址(只允许绑定本机器的网卡地址)
参数:
sockfd:描述符
addr:代表的是本机的IP地址和端口
addrlen:地址的长度返回值:0 -1

listen

int listen(int sockfd, int backlog);
作用:监听socket连接
参数:sockfd:描述符backlog:同时能处理的客户端的个数,随便赋值  5 10 15
返回值:0 -1

accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用:接收一个客户端的连接,它是一个阻塞接口,直到有客户端连入的时候,会退出阻塞
参数:sockfd:服务器的描述符addr:入参(你传入,接口给你赋值)addrlen:地址的长度
返回值:错误-1成功的话,会返回一个新的描述符,这个描述符代表的是客户端的一条链路

实例代码

客户端:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>#define N 64int main(int argc, char *argv[])
{if(argc < 3){printf("usage:%s <ip> <port>\n", argv[0]);return -1;}// 0定义变量int sockfd;char buf[N];int addrlen = sizeof(struct sockaddr);struct sockaddr_in serveraddr;// 1创建一个套接字--socketsockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket err");exit(-1);}// 2指定服务器地址--sockaddr_inbzero(&serveraddr, addrlen);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));// 3连接服务器--connectif(connect(sockfd, (struct sockaddr *)&serveraddr, addrlen) < 0){perror("connect err");exit(-1);}// 4收发数据--recv/sendwhile (1) {gets(buf);if(strcmp(buf, "quit") == 0){break;}send(sockfd, buf, N, 0);//接收服务器的消息bzero(buf, N);int len = recv(sockfd, buf, N, 0);if(len < 0){perror("recv err");break;}else if(len == 0){printf("server exit\n");break;}else{printf("recv server = %s\n", buf);}}// 5关闭连接--closeclose(sockfd);
}

服务器

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <netinet/ip.h> /* superset of previous */
#include <string.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//创建套接字int serverfd = socket(AF_INET, SOCK_STREAM, 0);if(serverfd < 0){perror("socket err");return -1;}//绑定自己的地址struct sockaddr_in myaddr;socklen_t addrlen = sizeof(myaddr);memset(&myaddr, 0, addrlen);myaddr.sin_family = AF_INET;myaddr.sin_port = htons(8888);
#if 0    myaddr.sin_addr.s_addr = inet_addr("192.168.51.193");
#elsemyaddr.sin_addr.s_addr = INADDR_ANY;
#endifint ret = bind(serverfd, (struct sockaddr *)&myaddr, addrlen);if(ret < 0){perror("bind err");return -1;}//启动监听ret = listen(serverfd, 5);if(ret < 0){perror("bind err");return -1;}//接收客户端的连接//定义代表客户端的结构体变量struct sockaddr_in cliaddr;int clifd = accept(serverfd, (struct sockaddr *)&cliaddr, &addrlen);if(clifd < 0){perror("accept err");return -1;}printf("新的连接过来了\n");printf("ip = %s, port = %d\n", inet_ntoa(cliaddr.sin_addr), \ntohs(cliaddr.sin_port)); #define N 64    char buf[N] = {0};while (1){//接收客户端的消息,如果客户端退出的话,服务器也退出//接收服务器的消息bzero(buf, N);int len = recv(clifd, buf, N, 0);if(len < 0){perror("recv err");break;}else if(len == 0){printf("client exit\n");break;}else{//回发给客户端printf("recv client = %s\n", buf);send(clifd, buf, N, 0);}}close(clifd);close(serverfd);return 0;
}

这篇关于网络编程——TCP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946496

相关文章

18.04版本的ubuntu没有连接网络的图标(坑人版)

以下更新内核别看,因为后面安装驱动报一堆错误!!! 不升级内核成功方法跳转连接:https://blog.csdn.net/weixin_53765004/article/details/138771613?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2213877

01并发编程的挑战

上下文切换 CPU通过时间片分配算法循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回来这个任务时,可以再次加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。频繁的上下文切换会影响多线程的执行速度 如何减少上下文切换 减少上下文切换的方法有无锁并发编程,CAS算法,使用最少线程和协程。无锁并发编程:多线程竞争锁时,

Java编程思想阅读笔记(第11章持有对象)

Java容器类类库的用途是“保存对象”并将其分为两个不同的概念 Collection。 一个独立元素的序列,这些元素服从一条或多条规则,List必须按照插入的顺序保存,而set不能有重复元素,Queue按照排队规则来确定对象产生的顺序(通常与它们插入的顺序相同)Map。一组成对的”键值对“对象,允许使用键查找。 浅谈Arrays.asList()方法的使用  首先,该方法是将数组转化为lis

Java编程思想阅读笔记(第10章内部类)

内部类 内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的可以将一个类的定义放在另一个类定义内部,这就是内部类内部类自动拥有对包裹它的基类所有成员的访问权限内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类 内部类的共性 内

Java编程思想阅读笔记(第九章接口)

抽象 - 包含抽象方法的类叫做抽象类,一个类中有一个或多个抽象方法,则这个类必须被指定为抽象类- 抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理- 子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。);- 抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类; - 抽象类中

202305青少年软件编程(Python)等级考试试卷(二级)

第 1 题 【单选题】 以下代码的输出结果是? ( ) s=[4, 2, 9, 1] s. insert(3, 3) print(s) A :[4, 2, 9, 1, 2, 3] B :[4, 3, 2, 9, 1] C :[4, 2, 9, 2, 1] D :[4, 2, 9, 3, 1]<

linux网络设置与网卡的简单设计

linux网络设置与网卡的简单设计 部分图片引用了他人的文章在这由衷表示感谢 一、系统如何识别网卡 1、在RHEL4中会以模块的方式来载入网卡的驱动程序 ·如果设定好在开机的时候启用网卡,开机后就会自动载入网卡的模块; ·依据 /etc/modprobe.conf 文件的设定来确认主机里面的网卡使用的是哪一个驱动程序; 2、在所有网络设定的文件或脚本文件里面,会用一个

Java编程如何写一个会导致死锁的程序?

第一次看到这个题目,觉得这是一个非常好的问题。很多人都知道死锁是怎么一回事儿:线程A和线程B相互等待对方持有的锁导致程序无限死循环下去。当然也仅限于此了,问一下怎么写一个死锁的程序就不知道了,这种情况说白了就是不懂什么是死锁,懂一个理论就完事儿了,实践中碰到死锁的问题基本上是看不出来的。 真正理解什么是死锁,这个问题其实不难,几个步骤: 1)两个线程里面共同持有两个Object对象:lock1

【Java EE】网络原理——TCP1

目录 1.TCP协议格式 2.TCP协议的特点 3.TCP协议的核心机制(十个) 3.1确认应答机制 3.2超时重传 3.3连接管理 3.3.1三次握手基本流程: 3.3.2三次握手的意义或者解决的问题:(面试题) 3.3.3三次握手时TCP的状态 3.3.4断开连接:四次挥手 3.3.5四次挥手的流程: 3.3.6四次挥手时TCP的状态转换 1.TCP协议格

[Linux][网络][协议技术][DNS][ICMP][ping][traceroute][NAT]详细讲解

目录 1.DNS1.DNS背景2.域名简介 2.ICMP协议1.ICMP功能2.ICMP两类报文 3.ping命令4.traceroute5.NAT技术1.NAT技术背景2.NAT IP转换过程3.静态地址NAT && 动态地址NAT4.网络地址端口转换NAPT5.NAT技术的缺陷6.NAT和代理服务器 6.总结1.数据链路层2.网络层3.传输层4.应用层 1.DNS DN