这是小老弟我第一次写博客,格式什么排版很忙的不好看的话就将就下啦,内容自我感觉还是可以的。
一、先建立几个概念
啥叫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…