Linux网络编程:Socket服务器和客户端实现双方通信

这篇具有很好参考价值的文章主要介绍了Linux网络编程:Socket服务器和客户端实现双方通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一,什么是网络编程

二,为什么使用端口号

三,TCP协议与UDP协议

①TCP(传输控制协议)

②UDP(用户数据报协议,User Data Protocol)

③总结归纳

四,Socket服务器和客户端的开发流程

五,服务器和客户端相关API说明

①socket()函数

②bind()函数

③listen()函数

④accept()函数

⑤客户端的connect()函数 

⑥数据收发:read() write()和send() recv()

● read() write()

● send() recv()

六,地址格式转换相关API

①ip地址字符串和网络格式转换(inet_aton)

②端口字节序转换(htons)

七,socket服务端和客户端的代码实现

①socket服务端代码(无客户端连接):

②客户端连接服务器端:

● 服务器端代码(server):

● 客户端代码(client):

● 编译结果:


一,什么是网络编程

网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用。网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计这5部分都需要接触。

二,为什么使用端口号

①一台拥有IP地址的主机可以提供一个IP地址来实现。那么,主机时怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系;

②实际上是通过“IP地址+端口号来区分不同服务的;

③端口提供了一种访问通道;

④服务器一般是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说。FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69;

三,TCP协议与UDP协议

①TCP(传输控制协议)

①提供IP环境下的数据可靠传输(一台计算机发出的字节流会无差错的发往网络上的其他计算机,而且计算机A接收数据包的时候,也会向计算机B回发数据包,这也会产生部分通信量),有效流控,全双工操作(数据在两个方向上能同时传递),多路复用服务,是面向连接,端到端的传输;

②面向连接:正式通信前必须要与对方建立连接。事先为所发送的数据开辟出连接好的通道,然后再进行数据发送,像打电话。

③TCP支持的应用协议:Telnet(远程登录)、FTP(文件传输协议)、SMTP(简单邮件传输协议)。TCP用于传输数据量大,可靠性要求高的应用。

②UDP(用户数据报协议,User Data Protocol)

1)面向非连接的(正式通信前不必与对方建立连接,不管对方状态就直接发送,像短信,QQ),不能提供可靠性、流控、差错恢复功能。UDP用于一次只传送少量数据,可靠性要求低、传输经济等应用。

2) UDP支持的应用协议:NFS(网络文件系统)、SNMP(简单网络管理系统)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。

③总结归纳

TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。
 

四,Socket服务器和客户端的开发流程

socket服务器和客户端,Linux网络编程,linux,网络,服务器,tcp/ip

服务器端

客户端

①socket()。创建socket ①socket()。创建socket
②bind()。绑定IP地址、端口等信息到socket返回的描述符上 ②结构体struct sockaddr_in设置要连接的对方的IP地址和端口等属性
③listen()。设置允许的最大连接数 ③connect()。连接服务器
④accept()。接收客户端上来的连接 ④read()和write(),send()和recv()。收发数据
⑤read()和write(),send()和recv()。收发数据 ⑤close()。关闭网络连接
⑥close()。关闭网络连接
注意:服务器端和客户端须使用相同的端口号和IP地址。

五,服务器和客户端相关API说明

①socket()函数

作用创建socket套接字,获取类似文件描述符的网络描述符。Linux中的网络编程通过Socket(套接字)接口实现。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//返回值:成功,则返回新套接字的文件描述符。失败返回-1,并设置errno。

▲ domain:指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);

     ●   AF_INET           IPv4因特网域

     ●   AF_INET6         IPv6因特网域;

     ●   AF_UNIX          Unix域;

     ●   AF_ROUTE      路由套接字;

     ●   AF_KEY           密钥套接字;

     ●   AF_UNSPEC   未指定;

▲ type:指定socket的类型;

     ●   SOCK_STREAM:流式套接字提供可靠的,面向连接的通信流;它使用TCP协议,从而保证数据传输的正确性和顺序性;

     ●   SOCK_DGRAM: 数据报套接字定义一种无连接的服,数据通过相互独立的报文进行传输,是无序的,不能保证是可靠,无差错,它使用UDP数据报协议;

     ●   SOCK_RAW:允许程序使用低层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。

procolto:通常赋值‘0’,默认协议;

     ●   "0"选择type类型对应的默认协议

     ●   IPPROTO_TCP   TCP传输协议

     ●   IPPROTO_UDP   UDP传输协议

     ●   IPPROTO_SCTP   SCTP传输协议

     ●   IPPROTO_TIPC   TIPC传输协议

②bind()函数

作用绑定IP地址、端口等信息到socket返回的描述符上(socketfd)

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//返回值:如果成功,则返回0。发生错误时,返回-1。errno设置错误码。

▲ sockfd:socket返回的描述符(socketfd);

▲addr:是指向包含本机IP地址及端口号信息的sockaddr类型的指针,指向绑定给sockfd的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。结构体如下:

▲addrlen:结构体大小sizeof();

sockaddr结构的两种原型:一般使用新版本struct sockaddr_in的结构体类型
struct sockaddr {
               u_short sa_family;  // 地址族或协议族,采用“AF_xxx”的形式,如:AF_INET  
               char sa_data[14];  //    IP+端口, 14字节的特定协议地址
}; 
对应IPv4,同等替换:

struct sockaddr_in {
                      short int    sin_family;        /* 地址族或协议族 */
                      unsigned short int    sin_port;      /* 端口号 */
                      struct in_addr    sin_addr;       /* IP地址结构体 */
                      unsigned char    sin_zero[8];      /* 填充 ,无实际意义,只是为跟sockaddr结构在内存中对齐,这样两者才能互相转换*/

};

struct in_addr{
                      unsigned long    s_addr;   // S_addr: 32位的地址
};

linux结构体查询步骤:①cd /usr/include/       ②grep "struct sockaddr_in {" * -nir         ③vi linux/in.h +显示的数字

③listen()函数

作用:监听套接字上的连接,设置能处理的最大连接数。不阻塞,告诉内核服务器能处理多少个连接队列。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//返回值:如果成功,则返回0。发生错误时,返回-1和errno设置正确。

▲sockfd:socket返回的描述符(socketfd);

▲backlog:设置在请求连接队列中能连接的最大请求数,直接用写数字即可。

④accept()函数

作用:阻塞,等待接收客户端上来的连接。由TCP服务器调用,用于从已完成连接队列头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//返回值:该函数返回值是一个新的套接字描述符,返回值表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述符。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在,内核为每个由服务器进程接受的客户连接创建一个已连接套接字(表示TCP三次握手已经完成),当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。失败返回-1,设置erron

▲sockfd:服务器端调用socket返回的描述符(socketfd);

▲addr:用来返回已连接的对端(客户端)的协议地址;

▲addrled:客户端地址长度。

⑤客户端的connect()函数 

作用:用于绑定后的client端(客户端),与服务器建立连接。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//返回值:如果连接或绑定成功,则返回0。失败,返回-1,并适当地设置errno。

▲socfd:服务端socket返回的描述符;

▲addr:服务器端IP地址和端口号的地址结构指针;(可以参考上面bind()函数中的结构指针);

▲addrlen:地址长度被设置为sizeof(struct socaddr);

⑥数据收发:read() write()和send() recv()

● read() write()

作用:在套接字通信中进行字节读取函数。与I/O中的读取函数略有区别,因为它们输入或输出的字节数可能比请求的数少。

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
//返回值:成功返回读或写的字节个数,出错返回-1

说明:第一个将buf中的nbytes个字节写入到文件描述符fd中,成功时返回写的字节数;第二个从fd中读取nbytes个字节到buf中,返回实际所读的字节数。

● send() recv()

作用:在TCP套接字上发送和接收数据函数:有连接

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//包含3要素:套接字s,待发数据msg,数据长度len;
//函数只能对处于连接状态的套接字使用,参数s为已读建立好连接的套接字描述符,即accept函数的返回值;
//参数msg指向存放待发送数据的缓冲区;
//参数len为待发送数据的长度,参数flag为控制选项,一般设置为0;
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//包含3要素:套接字s,接收缓冲区buf,长度len;
//函数recv从参数s所指定的套接字描述符(必须面向连接的套接字)上接收数据并保存到buf所指定的缓冲区;
//参数len为缓冲区长度,参数flags为控制选项,一般设置为0;

六,地址格式转换相关API

①ip地址字符串和网络格式转换(inet_aton)

说明:IP地址通常由数字加点(192.168.0.0)的形式表示,而在struct in_addr中使用的是IP地址是由32位的整数表示的,转换函数如下:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp,struct in_addr *inp)
//将字符串形式的“000.000.0.0”形式的IP转换为32位的IP(网络能识别的格式),存储在inp指针里面。
 
char *inet_ntoa(struct in_addr in) 
//是将32位IP(网络格式)转换为字符串“000.000.0.0”的格式

②端口字节序转换(htons)

说明:不同类型的 CPU 对变量的字节存储顺序可能不同:有的系统是高位在前,低位在后,而有的系统是低位在前,高位在后,而网络传输的数据顺序是一定要统一的。所以当内部字节存储顺序和网络字节顺序不同时,就一定要进行转换。网络字节顺序采用big endian(大端)排序方式。

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//把unsigned long类型从主机序转换到网络序
uint16_t htons(uint16_t hostshort);//把unsigned short类型从主机序转换到网络序//
uint32_t ntohl(uint32_t netlong);//把unsigned long类型从网络序转换到主机序
uint16_t ntohs(uint16_t netshort);//把unsigned short类型从网络序转换到主机序

函数说明:①h表示host,n表示network,l表示long(4字节),s表示short(2字节)。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

                  ②根据情况使用NADDR_ANY,INADDR_ANY指定地址让操作系统自己获取。

七,socket服务端和客户端的代码实现

①socket服务端代码(无客户端连接):

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
        //1 socket 创建套接字,获取描述符
        int socfd = socket(AF_INET,SOCK_STREAM,0);
        if(socfd == -1){
                perror("error socket");
        }

        //结构体struct sockaddr_in设置要连接的对方的IP地址和端口等属性
        struct sockaddr_in s_addr;
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(7777);
        inet_aton("127.0.0.1",&s_addr.sin_addr);

        //2 bind 绑定IP地址、端口等信息到socket返回的描述符上
        bind(socfd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

        //3 listen 设置允许的最大连接数
        listen(socfd,10);

        //4 阻塞 等accept接收客户端上来的连接请求 
        struct sockaddr_in c_addr;
        int clen = sizeof(struct sockaddr_in);
        int c_fd = accept(socfd,(struct sockaddr *)&c_addr,&clen);
        if(c_fd == -1){
                perror("error accept!\n");
        }

        //5 read 读取来自客户端上的请求信息
        char readBuf[128] = "masseag from client!";
        int n_read = read(c_fd,readBuf,128);
        if(n_read == -1){
                perror("read\n");
        }else{
                printf("read%dByte:%s\n",n_read,readBuf);
        }

        //6 write 收到客户端的请求信息后,回复信息给客户端
        char *msg = "I got your masseag!";
        write(c_fd,msg,strlen(msg));

        //7 关闭网络连接
        close(c_fd);

        return 0;
}

 编译结果:telnet 远程登陆协议

socket服务器和客户端,Linux网络编程,linux,网络,服务器,tcp/ip

②客户端连接服务器端:

● 服务器端代码(server):

​
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
        //1,socket 创建套接字,获取描述符
        int sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(sockfd == -1){
                perror("socket");
                exit(-1);
        }
        //2,bind 绑定IP地址和端口信息
        struct sockaddr_in s_addr;
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(6666);//字节序转换
        inet_aton("127.0.0.1",&s_addr.sin_addr);//IP地址格式转换

        bind(sockfd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

        //3,listen 设置监听数量,告诉内核本服务器能连接客户段的最大数量
        listen(sockfd,1);

        //4,accept 接受套接字的连接
        int clen = sizeof(struct sockaddr_in);
        int c_fd = accept(sockfd,(struct sockaddr *)&s_addr,&clen);
        if(c_fd == -1){
                perror("accept");
                exit(-1);
        }

        //5,read 服务器会先读到来至客户端的请求
        char readBuf[128];
        int n_read = read(c_fd,readBuf,128);
        if(n_read == -1){
                perror("read");
        }else{
                printf("read%dByte:%s\n",n_read,readBuf);
        }

        //6,write 服务器在收到客户端的请求后,会回信给客户端
        char *msg= "ok,I got your message!";
        write(c_fd,msg,strlen(msg));

        //7,关闭网络连接
        close(c_fd);

        return 0;
}

​

● 客户端代码(client):

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
        //1,socket 创建套接字,获取描述符
        int sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(sockfd == -1){
                perror("sockfd");
                exit(-1);
        }
        //结构体struct sockaddr_in设置要连接的对方的IP地址和端口等属性
        struct sockaddr_in s_addr;
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(6666);
        inet_aton("127.0.0.1",&s_addr.sin_addr);

        //2,connect 连接服务器
        if(connect(sockfd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr)) == -1){
                perror("connect");
        }

        //3,向服务器发送请求
        char buf[128] = "I set your message";
        write(sockfd,buf,strlen(buf));

        //4,读取来自服务器的回信
        char msg[128];
        int n_read = read(sockfd,msg,128);
        if(n_read == -1){
                perror("read");
        }else{
                printf("read%dByte:%s\n",n_read,msg);
        }

        //5,关闭网络连接
        close(sockfd);

        return 0;
}

● 编译结果:

socket服务器和客户端,Linux网络编程,linux,网络,服务器,tcp/ip文章来源地址https://www.toymoban.com/news/detail-667243.html

到了这里,关于Linux网络编程:Socket服务器和客户端实现双方通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

    ​ 哈喽,大家好~我是你们的老朋友: 保护小周ღ   本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信 ,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~ 本期收录于博主的专栏 : JavaEE_保

    2024年02月02日
    浏览(50)
  • 网络编程-Socket通信实现服务器与客户端互传文件(JAVA语言实现)

    在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换. 网络编程三要素:ip地址、端口、协议 ip地址: 每台计算机指定的一个标识符,127.0.0.1是回送地址,可以代表本机地址 ,一般用来测试使用 ipconfig:命令行中查看本机地址 ping ip地址:检查网络是

    2023年04月14日
    浏览(38)
  • 网络编程3——TCP Socket实现的客户端服务器通信完整代码(详细注释帮你快速理解)

    本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下! 今天分享的内容是TCP流套接字实现的客户端与服务器的通信,一定要理解 DatagramSocket,DatagramPacket 这两个类的作用以及方法

    2024年02月12日
    浏览(49)
  • Java【网络编程2】使用 TCP 的 Socket API 实现客户端服务器通信(保姆级教学, 附代码)

    📕各位读者好, 我是小陈, 这是我的个人主页 📗小陈还在持续努力学习编程, 努力通过博客输出所学知识 📘如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 📙 希望我的专栏能够帮助到你: JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统

    2024年02月05日
    浏览(50)
  • 【Linux网络编程】网络编程套接字(TCP服务器)

    作者:爱写代码的刚子 时间:2024.4.4 前言:本篇博客主要介绍TCP及其服务器编码 只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP地址 但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换 字符串转in

    2024年04月14日
    浏览(57)
  • 【网络编程】(TCP流套接字编程 ServerSocket API Socket API 手写TCP版本的回显服务器 TCP中的长短连接)

    TCP提供的API主要是两个类:ServerSocket 和 Socket . TCP不需要一个类来表示\\\"TCP数据报\\\"因为TCP不是以数据报为单位进行传输的.是以字节的方式,流式传输 ServerSocket API ServerSocket 是专门给服务器使用的Socket对象. ServerSocket 构造方法: ServerSocket(int port) 创建一个服务端流套接字Socket,并绑

    2024年02月12日
    浏览(53)
  • linux并发服务器 —— linux网络编程(七)

    C/S结构 - 客户机/服务器;采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互;C/S结构中,服务器 - 后台服务,客户机 - 前台功能; 优点 1. 充分发挥客户端PC处理能力,先在客户端处理再提交服务器,响应速度快; 2. 操作界面好看,满足个性化需求; 3.

    2024年02月09日
    浏览(65)
  • Linux学习之网络编程3(高并发服务器)

    Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。 问题: 根据上一个笔记,我们可以写出一个简单的服务端和客户端通信,但是我们发现一个问题——服务器只能连接一个

    2024年02月01日
    浏览(38)
  • Linux高性能服务器编程 学习笔记 第五章 Linux网络编程基础API

    我们将从以下3方面讨论Linux网络API: 1.socket地址API。socket最开始的含义是一个IP地址和端口对(ip,port),它唯一表示了使用TCP通信的一端,本书称其为socket地址。 2.socket基础API。socket的主要API都定义在sys/socket.h头文件中,包括创建socket、命名socket、监听socket、接受连接、发

    2024年02月07日
    浏览(46)
  • Linux网络编程:多进程 多线程_并发服务器

    文章目录: 一:wrap常用函数封装 wrap.h  wrap.c server.c封装实现 client.c封装实现 二:多进程process并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 三:多线程thread并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 ​​​​   read 函数的返回值 wrap.h  wrap

    2024年02月12日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包