网络socket编程(c语言)

article/2025/10/7 18:10:50

一.socket通信简介

Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议,主要利用三元组【ip地址,协议,端口】。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。
Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。Socket是应用层与TCP/IP协议族通信的中间软件抽象层。
在这里插入图片描述
二.网络socket客户端和服务器端连接过程如下:
在这里插入图片描述

1.1 socket()
int socket(int domain,int type, int protocol);
返回值: 成功:返回指向新创建的socket的文件描述符,失败:返回-1。

domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
type:创建的套接字的类型,常用SOCK_STREAM(流式套接字),SOCK_DGRAM(数据报套接字)

protocol: 传0 表示使用默认协议。

1.2 bind()
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
返回值:函数执行成功返回0,否则返回-1, 并设置错误代码。

sockfd:需要绑定的套接字文件描述符。
addr:存入网络类型,网络地址和端口号的结构体。
addrlen:addr结构体的长度。

ipv4使用的结构体是struct sockaddr_in类型,所以绑定时需要强制类型转换成struct sockaddr类型
struct sockaddr_in
{
sa_family_t sin_family; /* 2 bytes address family, AF_xxx such as AF_INET /
in_port_t sin_port; /
2 bytes port*/
struct in_addr sin_addr; /* 4 bytes IPv4 address*/
unsigned char sin_zero[8]; /* 8 bytes unused padding data, always set be zero */
};

struct sockaddr
{
sa_family_t sa_family; /* 2 bytes address family, AF_xxx /
char sa_data[14]; /
14 bytes of protocol address */
}

在使用bind时常用的两个函数:htonshtonl,在将一个地址绑定到socket的时候,先将主机字节序转换成为网络字节序
serv_addr.sin_port = htons(LISTEN_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

IP地址“127.0.0.1”这是点分十进制形式的字符串形式,而在结构体struct sockaddr_in 中IP地址是以32位(即4字节整形类型)数据保存的,这时我们可以调用 inet_aton() 函数将点分十进制字符串转换成 32位整形类型

1.3 listen()
int listen(int sockfd,int backlog);
返回值:成功返回0,失败返回-1。
sockfd: socket文件描述符
backlog: 排队建立3次握手队列和刚刚建立3次握手队列的链接数和

1.4 accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

属性相同的连接套接字,并为这个套接字分配一个文件描述符,然后以这个描述符返回
返回值:若成功则返回一个非负整数标识这个连接套接字,发生错误时返回-1。
sockfd:一个正在用于监听功能下的套接字的文件描述符。
addr:用于储存接受到的客户端的网络信息的结构体(参考bind下的使用)
addrlen:addr结构体长度

1.5 connect()
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockfd: 客户端的socket()创建的描述字
addr: 要连接的服务器的socket地址信息,这里面包含有服务器的IP地址和端口等信息
addrlen: socket地址的长度

客户端server.c程序编写

/**********************************************************************************      Copyright:  (C) 2021 jiaoer237*                  All rights reserved.**       Filename:  socket_server.c*    Description:  This file *                 *        Version:  1.0.0(11/21/2021)*         Author:  yanp <2405204881@qq.com>*      ChangeLog:  1, Release initial version on "11/21/2021 01:59:13 PM"*                 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define PORT 8899
#define BACKLOG 13int socket_server_init(char *listen_ip,int listen_port);int main()
{int listen_fd,clien_fd=-1;struct sockaddr_in cli_addr;socklen_t cliaddr_len;char buf[1024];int rv=-1;listen_fd=socket_server_init(NULL,PORT);/*初始化socket函数*/while(1){printf("\nstart waiting and accept new client connect...\n");clien_fd=accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);/*accept调用*/if(clien_fd<0){printf("accept new client failure:%s\n",strerror(errno));return -1;}printf("accept new client[%s:%d] with fd [%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),clien_fd);memset(buf,0,sizeof(buf));rv=read(clien_fd,buf,sizeof(buf));if(rv<0){printf("read data from socket[%d] failure:%s\n",clien_fd,strerror(errno));close(clien_fd);continue;}else if(0==rv){printf("read data from socket[%d] failure:%s\n",clien_fd,strerror(errno));close(clien_fd);continue;}printf("read %d data from server client [%d] and echo it back:'%s'\n",rv,clien_fd,buf);if(write(clien_fd,buf,rv)<0){printf("write %d bytes data back to client[%d] failure:%s\n",rv,clien_fd,strerror(errno));close(clien_fd);}}return 0;
}int socket_server_init(char *listen_ip,int listen_port)
{int listenfd;struct sockaddr_in servaddr;if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)/*创建socket描述符*/{printf("socket_server to create a TCP socket fd failure:[%s]\n",strerror(errno));return -1;}printf("create a tcp socket fd[%d] success\n",listenfd);int on=1;  if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) /*让端口号能够立即重复使用*/{printf("setsockopt failure:%s",strerror(errno));return -2;}memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(PORT);if(!listen_ip)/*加入传入IP地址则监听指定ip,否则监听所有ip*/{servaddr.sin_addr.s_addr=htonl(INADDR_ANY);}else{servaddr.sin_addr.s_addr=htonl(listen_port);}if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)/*绑定端口号和ip*/{printf("socket[%d] bind on port[%d] for ip address failure:%s\n",listenfd,listen_port,strerror(errno));return -2;}printf("socket[%d] bind on port[%d] for ip address success\n",listenfd,listen_port);listen(listenfd,BACKLOG);return listenfd;
}

服务器端client.c程序编写

/**********************************************************************************      Copyright:  (C) 2021 jiaoer237*                  All rights reserved.**       Filename:  socket_client.c*    Description:  This file *                 *        Version:  1.0.0(11/21/2021)*         Author:  yanp <2405204881@qq.com>*      ChangeLog:  1, Release initial version on "11/21/2021 08:49:25 PM"*                 ********************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define SERVER_PORT 8899
#define MSG_STR "Hello yanp, Unix Network Program World!"
#define SERVER_IP "192.168.1.120"int main(int argc,char **argv)
{int conn_fd = -1;int rv = -1;char buf[1024];struct sockaddr_in serv_addr;conn_fd=socket(AF_INET,SOCK_STREAM,0);/*socket创建客户端的描述符*/if(conn_fd<0){printf("create client socket failure:%s\n",strerror(errno));return -1;}memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERVER_PORT);inet_aton(SERVER_IP,&serv_addr.sin_addr);/*将点分十进制转换成32位整型类型*/if(connect(conn_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)/*连接服务器*/{printf("client[%d] connect to server[%s:%d] failure:%s\n",conn_fd,SERVER_IP,SERVER_PORT,strerror(errno));return -1;}if(write(conn_fd,MSG_STR,strlen(MSG_STR))<0){printf("write data to server[%s,%d] failure:%s\n",SERVER_IP,SERVER_PORT,strerror(errno));return -2;}memset(buf,0,sizeof(buf));rv=read(conn_fd,buf,sizeof(buf));if(rv<0){printf("read data from server failure:%s\n",strerror(errno));return -3;}else if(rv==0){printf("client connetc to server get disconnect\n");return -4;}printf("read %d bytes from server:'%s'\n",rv,buf);return 0;
}

在这里插入图片描述
在这里插入图片描述
客户端连接服务器之后进行读写操作


http://chatgpt.dhexx.cn/article/mprwovTB.shtml

相关文章

Socket的通信原理和使用

目录 一、什么是 Socket&#xff1f; 二、Socket 通信过程 2.1 通信过程介绍 2.2 实现TCP建立连接的三次握手过程 三、 使用Socket进行通信【php】 3.1 PHP中Socket常量和函数介绍 3.2 php实现Socket通信过程 一、什么是 Socket&#xff1f; Socket 的中文翻译过来就是“套接…

linux 网络编程socket

前言 socket&#xff08;套接字&#xff09;是linux下进程间通信的一种方式&#xff0c;通常使用C-S&#xff08;客户端-服务端&#xff09;的方式通信&#xff0c;它可以是同一主机下的不同进程间通信或者不同主机的进程通信。 socket是夹在应用层和TCP/UDP协议层间的软件抽象…

什么是socket?socket详解

“一切皆Socket&#xff01;” 话虽些许夸张&#xff0c;但是事实也是&#xff0c;现在的网络编程几乎都是用的socket。 ——有感于实际编程和开源项目研究。 我们深谙信息交流的价值&#xff0c;那网络中进程之间如何通信&#xff0c;如我们每天打开浏览器浏览网页时&#xff…

【Python】Socket的简单应用

前言 今天“出差在外”&#xff0c;晚上又琐事缠身&#xff0c;实在也没办法特别沉下心去学什么内容&#xff0c;但还是不希望一天一篇的flag就此倒下&#xff0c;只能多多参考别人的博客浅浅学习一下python的socket应用&#xff0c;后续课内做实验了&#xff0c;学习更深入的…

http和socket关系

一、先说下HTTP网络协议栈 二、连接过程 三、重点来了&#xff0c;TCP套接字编程&#xff0c;也就是所谓的socket 四、通过比较发现http和socket完全是两个不同的概念&#xff0c;http是应用层的&#xff0c;socket是传输层和网络层的&#xff0c;http要基于socket实现。httpcl…

SOCKET函数详解

socket原理 1.socket socket位于应用层和TCP/IP协议通信中间&#xff0c;抽象成一组接口 1.服务端首先初始化Socket(),然后和接口进行绑定bind()和监听listen(),然后调用accept()进行阻塞。 2.客户端初始化socket(),然后调用connect&#xff08;&#xff09;与服务端进行连接…

用大白话解释什么是Socket

好好学习&#xff0c;天天向上 本文已收录至我的Github仓库DayDayUP&#xff1a;github.com/RobodLee/DayDayUP&#xff0c;欢迎Star&#xff0c;更多文章请前往&#xff1a;目录导航 前言 我在去年就学习过Java中Socket的使用&#xff0c;但对于Socket的理解一直都是迷迷糊糊…

Socket详解

“一切皆Socket&#xff01;” 话虽些许夸张&#xff0c;但是事实也是&#xff0c;现在的网络编程几乎都是用的socket。 ——有感于实际编程和开源项目研究。 我们深谙信息交流的价值&#xff0c;那网络中进程之间如何通信&#xff0c;如我们每天打开浏览器浏览网页时&#xff…

Java socket详解

整理和总结了一下经常遇到的问题&#xff1a; 1. 客户端socket发送消息后&#xff0c;为什么服务端socket没有收到&#xff1f; 2. 使用while 循环实现连续输入&#xff0c;是不是就是多线程模式&#xff1f; 3. 对多线程处理机制不是很明白&#xff0c;希望详细讲解…

Socket的详细介绍

文章目录 前言1-Socket出现的原因1.1-Socket出现的背景1.2-Socket解决的问题 2-Socket的组成及关键点2.1-What&#xff1a;什么是Socket&#xff1f;2.2-How&#xff1a; Socket通信实现的步骤2.3-How&#xff1a; Socket编写流程 3-Socket的关键实现3.1-socket()函数创建套接字…

Socket到底是什么?

学习java网络编程一段时间后&#xff0c;突然被问到socket是什么&#xff1f;回答不上来&#xff0c;感觉很尴尬&#xff0c;于是赶紧是查阅资料。 网络由下往上分为 物理层 、数据链路层 、 网络层 、 传输层 、 会话层 、 表现层 和 应用层。 通过初步了解&#xff0c;我知道…

什么是Socket?

一、什么是Socket&#xff1f; 在计算机通信领域&#xff0c;socket 被翻译为“套接字”&#xff08;套接字主机端口号&#xff09;&#xff0c;它是计算机之间进行通信的一种约定或一种方式。通过 socket这种约定&#xff0c;一台计算机可以接收其他计算机的数据&#xff0c;也…

Socket的学习(一)什么是Socket?

本文参考的是《Socket通信原理》https://www.cnblogs.com/wangcq/p/3520400.html 一、TCP/IP UDP是什么&#xff1f; TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;即传输控制协议/网间协议&#xff0c;是一个工业标准的协议集&#xff0c…

整数划分(递归方法)

最近讲到了递归&#xff0c;老师布置了一道经典的整数划分问题&#xff0c;浏览了网上很多代码&#xff0c;还是似懂非懂&#xff0c;想找张清晰地展现递归过程的图片也没有&#xff0c;今天想了想&#xff0c;自己画了一张才发现&#xff0c;想完整清晰地表现这个过程确实真的…

递归算法--整数划分

何为整数划分&#xff1a; 所谓整数划分&#xff0c;是指把一个正整数n写成为 其中&#xff0c; 为正整数&#xff0c;并且 &#xff1b; 为n的一个划分。 如果 中的最大值不超过m&#xff0c;即 &#xff0c;则称它属于n的一个m划分。 例如&#xff1a;6的划分&#xff1a; 6…

递归实现整数划分

递归思想 递归是算法设计中的一种基本而重要的算法。递归方法通过函数调用自身将问题转化为本质相同但规模较小的子问题&#xff0c;是分治策略的具体体现。 不多废话&#xff0c;直接上故事 ->从前有座山&#xff0c;山上有座庙&#xff0c;庙里有个老和尚在给小和尚讲故…

复杂的整数划分

复杂的整数划分 又到了动态规划的时间了&#xff01; 记得我之前讲过的三要素哦 下面这一条题目其实思路并不是非常的难&#xff0c;但是在细节处理上要非常仔细&#xff0c;而且它有3个相互独立的动态规划问题。 总时间限制: 200ms 内存限制: 65536kB 描述 将正整数n 表…

整数划分(DP)

一个正整数 n 可以表示成若干个正整数之和&#xff0c;形如&#xff1a;nn1n2…nk&#xff0c;其中 n1≥n2≥…≥nk,k≥1。 我们将这样的一种表示称为正整数 n 的一种划分。 现在给定一个正整数 n&#xff0c;请你求出 n 共有多少种不同的划分方法。 输入格式 共一行&#x…

【算法】整数划分问题

描述 整数划分问题是算法中的一个经典命题之一。把一个正整数n表示成一系列正整数之和&#xff1a; 正整数n的这种表示称为正整数n的划分。正整数n的不同划分个数称为正整数n的划分数&#xff0c;记作P(n) 。 正整数6有如下11种不同的划分&#xff0c;所以P(6)11。 6 51 42, …

【递归】整数划分(C++)

一、什么是整数划分 所谓整数划分&#xff0c;是指把一个正整数n写成如下形式&#xff1a; n m 1 m 2 ⋅ ⋅ ⋅ m i nm_1m_2m_i nm1​m2​⋅⋅⋅mi​&#xff1b; 其中 m i m_i mi​为正整数&#xff0c;并且 1 ≤ m i ≤ n 1 \leq m_i \leq n 1≤mi​≤n&#xff0c;则 { …