基于TCP的Socket网络编程

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

前言:
Socket通信是基于TCP/IP协议的通信。在工作和做项目中应用非常广,下面来介绍下Socket网络编程!

Socket的介绍

首先,在Socket网络编程中我们要了解两个重要的东西,ip和端口号,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。这些服务完全可以通过1个ip地址来实现。主机是怎样区分不同的网络服务的?显然不能只靠ip地址,因为ip地址与网络服务的关系是一对多的关系。
实际上是通过“ip地址+端口号”来区分不同的服务的。一般端口号在5000~10000。

1.字节序

字节序:指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
Little endian(小端字节序):将低序字节存储在起始地址。
Big endian(大端字节序):将高序字节存储在起始地址。

举个例子:int a = 0x12345678;
0x78属于低地址,而0x12属于高地址
如果是大端模式,那输出方式是0x12 0x34 0x56 0x78,如果是小端模式,那么就是0x78 0x56 0x34 0x12

这个很容易理解,人类读写数据的习惯是大端字节序,而小端字节序是反着人类来的,而我们网络字节序传输是大端模式,因此要转为大端模式。

2.字节序转换api:
 #include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值uint32_t
 htonl(uint32_t host32bitvalue);    //返回网络字节序的值uint16_t ntohs(uint16_t
 net16bitvalue);     //返回主机字节序的值uint32_t ntohl(uint32_t net32bitvalue);
 //返回主机字节序的值

 h代表host,n代表net,s代表short(两个字节),l代表long4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

Socket的开发步骤

Socket服务器和客户端的开发步骤:
基于TCP的Socket网络编程

Linux提供的API简析

1.socket(创建套接字)

int socket(int domain, int type, int protocol);

基于TCP的Socket网络编程

2.bind()函数
 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>

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

功能:用于绑定ip地址跟端口号到socketfd。
 参数说明:
 sockfd--是一个文件描述符
 addr:是一个指向包含有本地IP及端口号等信息等信息的sockaddr类型的指针,指向要绑定给socket的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。

基于TCP的Socket网络编程

struct sockaddr_in结构体:

 struct sockaddr_in
 {  
	 sa_family_t sin_family; //指定AF_***,表示使用什么协议族的ip格式  __be16       sin_port;   //设置端口号  struct
	 in_addr  sin_addr;   //设置ip  
	 unsigned char  __pad[__SOCK_SIZE__ -sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
 }; 

struct in_addr
{  
	__be32 s_addr;  //32位的无符号整型数据 
}; 

bind函数绑定实例:

此结构体因为成员中设置ip和端口的变量时分开的,所以设置方便,但是bind函数要求的是struct sockaddr类型的结构体变量,所以使用struct sockaddr_in设置以后要将其强制转化为struct sockaddr类型,然后传值给bind函数。

 struct sockaddr_in addr;  //首先定义结构体变量
 addr.sin_family = AF_INET;  //指定协议族为IPV4版本的TCP/IP协议族 addr.sin_port =
 htons(5006);  //指定端口号 addr.sin_addr.s_addr =
 inet_addr("192.168.1.10"); //指定IP ret = bind(sockfd,(struct
 sockaddr*)&addr,sizeof(sddr)); //进行套接字文件/ip/端口的绑定
htons函数

功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian);

 #include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
addr.sin_port = htons(5006);
inet_addr函数

功能:将一个字符串格式的ip地址转换成一个uint32_t数字格式。

 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 in_addr_t inet_addr(const char *cp);
 eg:
 addr.sin_addr.s_addr = inet_addr("192.168.1.10");
地址转换API
  int inet_aton(const char* straddr,struct in_addr *addrp);
   把字符串形式的“192.168.1.123”转为网络能识别的格式
 
 
 char* inet_ntoa(struct in_addr inaddr);  把网络格式的ip地址转为字符串形式
3.listen()函数
 #include <sys/types.h>
 #include <sys/socket.h>
 
 int listen(int sockfd, int backlog);
功能:监听设置函数
 参数说明:
 sockfd:文件描述符
 backlog:指定在请求队列中允许的最大请求数
4.accept()函数
 #include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
 int accept(int sockfd, struct sockaddr *addr, socklen_t*addrlen);
 
 功能:accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接,如果已完成连接队列为空,那么进程被投入睡眠。
 
 参数说明:
sockfd:文件描述符
addr:用来返回已连接的对端(客户端)的协议地址
addrled:客户端地址长度
返回值:accept函数返回值成功时返回非负值,失败时返回-1
5.1. 数据收发(recv 、send)
函数原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
 
功能:向套接字中发送数据
参数:
 sockfd:向套接字中发送数据
 buf:要发送的数据的首地址
 len:要发送的数据的字节
  int flags:设置为MSG_DONTWAITMSG 时 表示非阻塞 设置为0时 功能和write一样
返回值:成功返回实际发送的字节数,失败返回 -1 


 函数原型:ssize_t recv(int sockfd, const void *buf, size_t len, int flags);

 功能:向套接字中发送数据 
 参数: 	  
sockfd:在哪个套接字接
buf:存放要接收的数据的首地址
len:要接收的数据的字节
int flags:设置为MSG_DONTWAITMSG 时 表示非阻塞设置为0时 功能和read一样        
返回值:成功返回实际发送的字节数,失败返回 -1
5.2. 数据收发(read 、write)
 #include <unistd.h>
 ssize_t read(int fd, void * buf, size_t nbytes);
 #include <unistd.h>
ssize_t write(int fd, const	void *buf, size_t nbytes);
6.客户端的connect函数
#include <sys/types.h> /* See NOTES */
 #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 
 
 参数说明:
 sockfd: socket文件描述符
 addr: 传入参数,指定服务器端地址信息,含IP地址和端口号 
 addrlen: 传入参数,传入sizeof(addr)大小 
 返回值:成功返回0,失败返回-1,设置errno
7. 一个客户端与服务器连接的demo

服务器:

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <stdlib.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char **argv)
{
        int s_fd;
        int c_fd;
        int ret;
        int n_read;
        char readBuf[128];
        char msg[128]={0};
        // char *writeBuf="I get your message!";
        int mark=0;
        //1.socket
        s_fd = socket(AF_INET,SOCK_STREAM ,0);
        if(s_fd == -1){

                perror("socket");
                exit(-1);
        }

        if(argc!=3){
                printf("pamrm error\n");
                exit(-1);
        }

        struct sockaddr_in a_addr;
        struct sockaddr_in c_addr;
        memset(&a_addr,0,sizeof(struct sockaddr_in));
        memset(&c_addr,0,sizeof(struct sockaddr_in));

        a_addr.sin_family=AF_INET;
        a_addr.sin_port=htons(atoi(argv[2]));
        a_addr.sin_addr.s_addr=inet_addr(argv[1]);
        //  inet_ntoa("172.20.10.3",&addr.sin_addr.s_addr);
        //2.bind
        ret = bind(s_fd,(struct sockaddr*)&a_addr,sizeof(struct sockaddr_in));
        if(ret==-1){
                perror("bind");
                exit(-1);
 }
        //3.listen
        int len=sizeof(struct sockaddr_in);
        listen(s_fd,10);

        while(1){
                //4.accept
                c_fd = accept(s_fd,(struct sockaddr*)&c_addr,&len);
                mark++;
                printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));
                if(fork()==0){
                        if(fork()==0){
                                while(1){
                                        sprintf(msg,"Welcome to No%d client\n",mark);
                                        write(c_fd,msg,strlen(msg));
                                        sleep(3);
                                }
                        }
                        //5.read
                        while(1){
                                memset(readBuf,0,sizeof(readBuf));
                                n_read=read(c_fd,readBuf,128);
                                if(n_read==-1){
                                        perror("read");
                                }else{
                                        printf("get:%s\n",readBuf);
                                }
                        }
                              break;
                }
                //6.write
        }
        return 0;
}

客户端:文章来源地址https://www.toymoban.com/news/detail-500062.html

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

int main(int argc,char **argv)
{
        int c_fd;
        int ret;
        int n_read;
        char msg[128]={0};
        char readBuf[128]={0};

        c_fd=socket(AF_INET,SOCK_STREAM,0);
        if(c_fd==-1){
                perror("socket");
                exit(-1);
        }

        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port=htons(atoi(argv[2]));
        addr.sin_addr.s_addr=inet_addr(argv[1]);

        ret=connect(c_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
        if(ret==-1){
                perror("connect");
                exit(-1);
        }

        while(1){

                if(fork()==0){
                        while(1){
                                memset(msg,0,sizeof(msg));
                                printf("input ");
                                gets(msg);
                                write(c_fd,msg,sizeof(msg));
                        }
                }
 while(1){

                        memset(readBuf,0,sizeof(readBuf));
                        n_read=read(c_fd,readBuf,sizeof(readBuf));
                        if(n_read==-1){

                                perror("read");
                        }else{
                                printf("get:%s\n",readBuf);
                        }

                }





        }





        return 0;
}



到了这里,关于基于TCP的Socket网络编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

    为什么需要网络编程? 现在网络普及程序越来越高,网络上保存着我们日常生活中需要的各种资源,使用程序通过网络来获取这些资源的过程就需要网络编程来实现。 什么是网络编程? 网络编程,指网络上的主机,通过不同的进程以程序的方式实现网络通信(网络数据传输)

    2024年02月17日
    浏览(79)
  • 【网络编程】网络编程概念,socket套接字,基于UDP和TCP的网络编程

    前言: 大家好,我是 良辰丫 ,今天我们一起来学习网络编程,网络编程的基本概念,认识套接字,UDP与TCP编程.💞💞💞 🧑个人主页:良辰针不戳 📖所属专栏:javaEE初阶 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期待大家三连,关注

    2023年04月20日
    浏览(61)
  • Java中的网络编程------基于Socket的TCP编程和基于UDP的网络编程,netstat指令

    Socket 在Java中,Socket是一种用于网络通信的编程接口, 它允许不同计算机之间的程序进行数据交换和通信 。Socket使得网络应用程序能够通过TCP或UDP协议在不同主机之间建立连接、发送数据和接收数据。以下是Socket的基本介绍: Socket类型 :在Java中,有两种主要类型的Socket,分

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

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

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

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

    2024年02月05日
    浏览(64)
  • 【Java】--网络编程:基于TCP协议的网络通信

    TCP协议(Transmission Control Protocol),即传输控制协议,是一种 面向连接 的, 可靠 的,基于 字节流 的传输层通信协议。数据大小无限制。 建立连接的过程需要 三次握手 。 断开连接的过程需要 四次挥手 。 使用TCP协议的通信双方分别为 客户端 和 服务器端 。 客户端负责向服务

    2024年01月23日
    浏览(60)
  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

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

    2024年02月02日
    浏览(71)
  • 基于UDP/TCP的网络通信编程实现

    红色是心中永不褪色的赤诚 操作系统为网络编程提供了 Socket api , Socket是基于TCP/IP协议的网络通信的基本单元, 基于Socket的网络程序开发就是 网络编程. 由于直接与应用层联系的是传输层, 所以针对应用层协议(TCP, UDP), Shocket提供了三种套接字, 分别是 流套接字(使用TCP) , 数据报

    2024年02月08日
    浏览(54)
  • 网络编程day2——基于TCP/IP协议的网络通信

            计算机S                                                 计算机C      创建socket对象                                   创建socket对象      准备通信地址(自己的ip(非公网ip))      准备通信地址                                     (计算

    2024年02月10日
    浏览(68)
  • 【网络编程】TCP Socket编程

    流套接字: 使用传输层TCP协议 TCP: 即Transmission Control Protocol(传输控制协议),传输层协议。 TCP的特点: 有连接 可靠传输 面向字节流 有接收缓冲区,也有发送缓冲区 大小不限 ServerSocket 是 创建TCP服务端Socket 的API。 注意: ServerSocket 只能用于 服务器端。 构造方法: 方法签名

    2024年02月07日
    浏览(49)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包