首页 > [linux][c语言]用socket实现简单的服务器客户端交互

[linux][c语言]用socket实现简单的服务器客户端交互

Socket解释:

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

socket交互原理图解

连接过程:

根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。

(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

socket连接过程图解

mac环境编译

client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include   /* netdb is necessary for struct hostent */#define PORT 4321   /* server port */#define MAXDATASIZE 100int main(int argc, char *argv[])
{int sockfd, num;    /* files descriptors */char buf[MAXDATASIZE];    /* buf will store received text */struct hostent *he;    /* structure that will get information about remote host */struct sockaddr_in server;if (argc != 2){printf("Usage: %s 
",argv[0]);exit(1);}if((he=gethostbyname(argv[1]))==NULL){printf("gethostbyname() error
");exit(1);}if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1){printf("socket() error
");exit(1);}bzero(&server,sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr = *((struct in_addr *)he->h_addr);if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1){printf("connect() error
");exit(1);}char str[] = "你好啊服务器!
";if((num=send(sockfd,str,sizeof(str),0))==-1){printf("send() error
");exit(1);}if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1){printf("recv() error
");exit(1);}buf[num-1]='';printf("server message: %s
",buf);close(sockfd);return 0;
}

server.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include #define PORT 4321#define BACKLOG 1
#define MAXRECVLEN 1024int main(int argc, char *argv[])
{char buf[MAXRECVLEN];int listenfd, connectfd;   /* socket descriptors */struct sockaddr_in server; /* server's address information */struct sockaddr_in client; /* client's address information */socklen_t addrlen;/* Create TCP socket */if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){/* handle exception */perror("socket() error. Failed to initiate a socket");exit(1);}/* set socket option */int opt = SO_REUSEADDR;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1){/* handle exception */perror("Bind() error.");exit(1);}if(listen(listenfd, BACKLOG) == -1){perror("listen() error. 
");exit(1);}addrlen = sizeof(client);while(1){if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1){perror("accept() error. 
");exit(1);}struct timeval tv;gettimeofday(&tv, NULL);printf("You got a connection from client's ip %s, port %d at time %ld.%ld
",inet_ntoa(client.sin_addr),htons(client.sin_port), tv.tv_sec,tv.tv_usec);int iret=-1;while(1){iret = recv(connectfd, buf, MAXRECVLEN, 0);if(iret>0){printf("%s
", buf);}else{close(connectfd);break;}/* print client's ip and port */send(connectfd, buf, iret, 0); /* send to the client welcome message */}}close(listenfd); /* close listenfd */return 0;
}

命令行执行 $ gcc client.c -o client,可以编译出客户端程序。

命令行执行$ gcc server.c -o server,可以编译出服务端程序。

命令行执行$ ./server,启动server程序。

重新打开一个命令行窗口

执行 $ ./client 127.0.0.1,启动客户端程序

本程序客户端会自动退出,服务器不会,因此如果想停掉服务器程序,直接在命令行界面按键盘Ctrl+C停止。

程序实现的功能很简单,就是服务器监听4321端口,客户端与之建立TCP连接后,再发送字符串“你好啊服务器! ”到服务端,服务端打印出来,然后再把字符串传回给客户端,客户端再打印出来。然后客户端关闭连接退出,而服务端继续监听4321端口等待下一次连接。

转载于:https://www.cnblogs.com/-oreo/p/10013216.html

更多相关:

  • 文章目录搭建实验平台使用Unity的准备工作在PC端安装连接Hololens软件Hololens设置开始连接吧绘制显示PC端网页监控...

  •  将多次卷积和池化后的图像展开进行全连接,如下图所示。  全连接层需要把输入拉成一个列项向量          比如你的输入的feature map是2X2,那么就需要把这个feature map 拉成4X1的列向量,如果你的feature map 的channels是3,也就是你的输入是3X2X2,也就是相当于有了12个像素点,...

  •   注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客 首先安装 cnpm i nodejs-websocket 在/a...

  • Ubuntu 配置自带桌面共享 1、在setting>>shareing>>remote 选择on 如果用ubunutu直接远程连接的话已经可以了, 2、在ubuntu下使用系统自带的remmina连接 vnc类型 直接输入ip地址 3、如果在windows下面连接的话需要把加密选项关闭 内容: 安装dconf-edito...

  • 第四节 RabbitMQ在C#端的应用-客户端连接 原文:第四节 RabbitMQ在C#端的应用-客户端连接 版权声明:未经本人同意,不得转载该文章,谢谢 https://blog.csdn.net/phocus1/article/details/87357911 1.在VS2013中新建控制台程序,然后添加引用:.NE...

  • 关于点云的分割算是我想做的机械臂抓取中十分重要的俄一部分,所以首先学习如果使用点云库处理我用kinect获取的点云的数据,本例程也是我自己慢慢修改程序并结合官方API 的解说实现的,其中有很多细节如果直接更改源程序,可能会因为数据类型,或者头文件等各种原因编译不过,会导致我们比较难得找出其中的错误,首先我们看一下我自己设定的一个场景,...

  • /* 使用正态分布变换进行配准的实验 。其中room_scan1.pcd room_scan2.pcd这些点云包含同一房间360不同视角的扫描数据 */ #include #include #include #include

  • #include #include #include #include ...

  • #include #include #include #include #include #include...

  • #include #include #include #include int main (int argc,...