TCP套接字编程简单示例

本文介绍了TCP(传输控制协议)的基本概念,解释了面向连接的特性及其实现机制。进一步探讨了套接字的概念,即IP地址和端口号如何共同实现端到端的通信。文章还详细讲解了TCP套接字编程的原理,包括服务器端和客户端的编程流程,并提供了具体的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是小老弟我第一次写博客,格式什么排版很忙的不好看的话就将就下啦,内容自我感觉还是可以的。

一、先建立几个概念

啥叫TCP?
搜狗百科上这么定义:TCP(Transmission Control Protocol),即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。如果读者目前还没有计算机网络的相关概念的话,这么定义还是比较晦涩难懂的。简单而言呢,它就是一种协议,即一种约定好了的传输数据的一种方式,且这种方式十分可靠,基本上讲无差错、无重复。那么,面向连接怎么理解?就是说发送数据前得先建立连接,通信完了得关闭连接,具体机制即是计算机网络的三次握手与四次挥手,这里就不详细展开了,读者自行找计算机网络知识补充吧。

啥叫套接字呢?
我的简单理解就是:
套接字=IP:PORT。IP确定是哪台主机或哪台设备,PORT(端口号)确定哪个进程(或者说哪个应用程序)。两者结合起来正是实现了端到端的通信机制,确保了打算发给B的QQ的信息,既不会发给了C,也不会发给了B的微信,就只是发给B的QQ上。

那啥叫 TCP套接字呢 ?
组合起来就得了,TCP套接字是面向连接的套接字,它提供面向连接的、可靠的数据传输。

二、原理

TCP套接字编程原理用下面这种流程图(图片来源网络,借来用用)理解最清晰明了了。通信嘛,自然是双方的事儿啦,这里一个当服务器端,一个当客户端,编写两个程序,具体流程如下:
图片来源网络服务器端:
(1)服务器端用socket()函数创建一个套接字,且后面就用这个套接字完成监听与通信功能。
(2)服务器用bind()函数绑定一个端口号与IP地址,即套接字=IP:PORT,确定通信对象。
(3)服务器用listen()函数对指定对象(端口号)进行监听,等待客户端的连接请求。
(4)假定客户端发起连接请求了,服务器端调用accept()函数接收请求,建立起与客户端的通信连接。
(5)这时可以相互通信了,发write()/send(),收read()/recv()。
(6)完成通信后,用close()函数关闭socket连接。

客户端
(1)客户端也要用socket()函数创建套接字。
(2)客户端调用connect()函数请求与服务器端的通信连接。事实上,这个connect()函数就封装了TCP协议的三次握手机制。
(3)连接上后,进行通信,发write()/send(),收read()/recv()。
(4)完成通信后,用close()函数关闭socket连接。

至此,TCP套接字编程的原理已经讲完啦,至于那些具体的函数,man一下或者百度一下就可以了。

三、示例源代码

服务器端

1 #include<stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>          /* See NOTES */
  4 #include <sys/socket.h>
  5 #include <string.h>
  6 #include <sys/socket.h>
  7 #include <unistd.h>
  8 #include <netinet/in.h>
  9 #include <arpa/inet.h>
 10 #include <errno.h>
 11 
 12 #define   BUFSIZE    1024
 13 int main(int argc,char *argv[] )
 14 {
 15     int sockfd,newsockfd;
 16     struct sockaddr_in server_addr; //定义服务器套接字数据结构server_addr
 17     struct sockaddr_in client_addr; //定义服务器套接字数据结构client_addr
 18     int portnumber;
 19     char buf[BUFSIZE];  //发送数据缓冲区
 20     int addr_len = sizeof(struct sockaddr_in);
 21     //判断命令行参数
 22     if(argc!=2){
 23         printf("Arguments error!Usage : %s portnumber\n",argv[0]);
 24         exit(1);
 25     }
 26     //获取命令行第二个参数----段口号,atoi把字符串转换成整数
 27     if((portnumber=atoi(argv[1]))<0){
 28         printf("Portnumber error!Usage:%s portnumber\n",argv[0]);
 29         exit(1);
 30     }
 31     //创建服务器SOCKET
 32     if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){
 33         printf("Create socket error:%s\n",strerror(errno));
 34         exit(1);
 35     }
 36     printf("Create server socket success!socket ID:%d\n",sockfd);
 37     //服务器填充sockaddr结构
 38     bzero(&server_addr,sizeof(struct sockaddr_in));//先将套接字地址数据结构清零
 39     server_addr.sin_family=AF_INET;
 40     server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
 41     server_addr.sin_port=htons(portnumber);
 42     //调用bind函数绑定端口
 43     if(bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr))== -1){
 44         printf("Bind error:%s\n",strerror(errno));
 45         exit(1);
 46     }
 47     printf("Bind port success!local port: %d\n",portnumber);
 48     //监听sockfd描述符,同时处理的最大连接请求数为5
 49     if(listen(sockfd,5)== -1){
 50         printf("Listen error:%s\n",strerror(errno));
 51         exit(1);
 52     }
 53     printf("Listening.......\n");
 54     //服务器阻塞,等待接收连接请求,直到客户端程序发送连接请求
 55     while(1){
 56         //调用accept接收一个连接请求
 57         if((newsockfd=accept(sockfd,(struct sockaddr*)(&client_addr),&addr_len))== -1){
 58             printf("Accept error:%s\n",strerror(errno));
 59             exit(1);
 60         }
 61         printf("server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
 62         //TCP连接已经建立,打印申请连接的客户端的IP地址
 63         printf("Connected successful,pls input the message[< 1024 bytes ]:\n");
 64         //提示用户输入将要发送的数据,长度小于缓冲区的长度,即1024B
 65
 66         //发送数据
 67         //从终端输入的数据存放在buf数据缓冲区中
 68         if(fgets(buf,sizeof(buf),stdin)!=buf){
 69             printf("fgets error!\n");
 70             exit(1);
 71         }
 72         if(write(newsockfd,buf,strlen(buf))== -1){
 73             printf("write error:%s\n",strerror(errno));
 74             exit(1);
 75         }
 76         close(newsockfd);//通信结束,关闭客户机的套接字,并循环下一次等待
 77     }
 78     close(sockfd);//服务器进程结束,关闭服务器套接字
 79     return 0;
 80 }

客户端

 1 #include<stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/types.h>
  5 #include <sys/socket.h>
  6 #include <errno.h>
  7 #include <netdb.h>
  8 
  9 #include <string.h>
 10 
 11 //定义数据缓冲区大小
 12 #define    BUFSIZE    1024    
 13 int main(int argc,char *argv[])
 14 {
 15     int sockfd;
 16     char buffer[BUFSIZE];
 17     struct sockaddr_in server_addr; //定义服务器套接字数据结构server_addr;
 18     struct hostent * hostname;
 19     int portnumber,nbytes;
 20     if(argc!=3){
 21          printf("Arguments error!Usage:%s hostname portnumber \n",argv[0]);
 22          exit(1);
 23     }
 24     //获得命令行第二个参数---主机名
 25     if((hostname=gethostbyname(argv[1]))== NULL){
 26         printf("Get hostname error!\n");
 27         exit(1);
 28     }
 29     //获得命令行的第三个参数----段口号,atoi()把字符串转换成整型数
 30     if((portnumber=atoi(argv[2]))<0){
 31         printf("Usage:%s hostname portnumber\n",argv[0]);
 32         exit(1);
 33     }
 34     //客户端程序开始建立sockfd描述符
 35     if((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1){
 36         printf("create socket error:%s\n",strerror(errno));
 37         exit(1);
 38     }
 39     printf("create client socket successful!socket id : %d\n",sockfd);
 40     //客户端程序填充服务器的资料
 41     bzero(&server_addr,sizeof(server_addr));
 42     server_addr.sin_family=AF_INET;
 43     server_addr.sin_port=htons(portnumber);
 44     server_addr.sin_addr=*((struct in_addr*)hostname->h_addr);
 45     //客户端程序发起连接请求
 46     if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr))== -1){
 47         printf("connect error:%s\n",strerror(errno));
 48         exit(1);
 49     }
 50     //连接成功,调用read读取服务器发送来的数据
 51         if((nbytes=recv(sockfd,buffer,BUFSIZE,0))== -1){
 52             printf("recv error:%s\n",strerror(errno));
 53             exit(1);
 54         }
 55         buffer[nbytes]='\0';
 56         printf("I have received :%s\n",buffer);
 57     close(sockfd);
 58     return 0;
 59 }

小老弟第一次写博客ha,有不对的或者有什么好建议欢迎大神提出,向大神学习ing…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值