zoukankan      html  css  js  c++  java
  • Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三)

    server端的简单示例

    经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去。

    绑定socket到一个端口上

    bind()函数可以将socket绑定到一个端口上,client可以通过向这个端口发起请求,端口对应的socket便会与client端的socket连接。

    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    
    int main() {
    	int socket_desc;
    	struct sockaddr_in server;
    	
    	socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    	if (-1 == socket_desc) {
    		perror("cannot create socket");
    		exit(1);
    	}
    	
    	// 监听服务器自身
    	server.sin_addr.s_addr = INADDR_ANY;
    	server.sin_family = AF_INET;
    	server.sin_port = htons(8888);
    	
    	// 绑定到端口
    	if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
    		perror("cannot bind error");
    		exit(1);
    	}
    	
    	printf("bind success");
    	
    	close(socket_desc);
    	return 0;
    }
    

    对于server.sin_addr.s_addr的更多信息可以参考这里

    通过将socket绑定到一个确定的端口上,我们接下来要做的便是接收这个端口下的所有数据。

    通过上面的实现,可以看出一个端口只能被一个socket使用。

    监听端口

    在绑定玩socket与端口后,我们还需要去监听端口。为此,我们需要将socket设置在被监听的状态下。listen()被用来将socket设置为被监听的模式下。

    listen(socket_desc, 3);
    

    listen(int sockfd, int backlog)可以将socket处于监听的状态。
    其参数为:

    1. int sockfd 设置监听的socket
    2. int backlog 在当前连接后面允许存在的最大未处理连接数

    当监听到新的请求来临时,server需要接收请求建立连接。

    接收请求建立连接

    函数accept()的作用便是接收请求。

    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    
    int main() {
    	int socket_desc, new_socket, sockaddr_size;
    	struct sockaddr_in server, client;
    	
    	// 创建socket
    	socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    	if (-1 == socket_desc) {
    		perror("cannot create socket");
    		exit(1);
    	}
    	
    	server.sin_addr.s_addr = INADDR_ANY;
    	server.sin_family = AF_INET;
    	server.sin_port = htons(8888);
    	
    	// 绑定
    	if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
    		perror("bind error");
    		exit(1);
    	}
    	
    	// 监听
    	listen(socket_desc, 5);
    	
    	puts("waiting for incoming connections....");
    	
    	// 接受
    	sockaddr_size = sizeof(struct sockaddr_in);
    	new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t *)&sockaddr_size);
    	if (new_socket < 0) {
    		perror("accept error");
    		exit(1);
    	}
    	
    	puts("connection accepted");
    	// 先关闭由socket_desc产生的new_socket
    	close(new_socket);
    	// 在关闭socket_desc
    	close(socket_desc);
    	return 0;
    }
    

    运行代码,他将会输出:

    waiting for incoming connections....
    

    现在代码已经正常的跑起来了,并且等待请求连接。在另外一个终端内,我们发起一个请求:

    telnet 127.0.0.1 8888
    

    在当前的这个终端内将会输出:

    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Connection closed by foreign host.
    

    同时在之前的终端内,server会输出:

    waiting for incoming connections....
    connection accepted
    

    便可以看到server已经正确的接受了client的连接请求并建立了连接,只是没有后续操作,主机紧接着关闭了这个连接。

    连接建立之后便可以顺利的进行双方的通信,这部分的sendrecv操作完全一样。

    另外:

    服务端获取客户端的IP地址

    由前面能够知道accept()返回的是结构体sockaddr_in,由此很容易得知client的IP和端口信息。

    char *client_ip = inet_ntoa(client.sin_addr);
    int client_port = ntohs(client.sin_port);
    
    server端的总结:
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<sys/socket.h>
    #include<sys/types.h>
    #include<arpa/inet.h>
    #include<netinet/in.h>
    #include<unistd.h>
    
    int main() {
    	int socket_desc, new_socket;
    	struct sockaddr_in server, client;
            char *message, get_recv[2000];
    	
    	// 创建socket
    	socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    	if (-1 == socket_desc) {
    		perror("cannot create socket");
    		exit(1);
    	}
    	
    	server.sin_addr.s_addr = INADDR_ANY;
    	server.sin_family = AF_INET;
    	server.sin_port = htons(8888);
    	
    	// 绑定
    	if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
    		perror("cannot bind");
    		exit(1);
    	}
    	puts("bind success");
    	
    	// 监听
    	listen(socket_desc, 5);
    	puts("waiting for incoming connections....");
    	
    	// 接受连接
    	socklen_t sockaddr_size = sizeof(client);
    	new_socket = accept(socket_desc, (struct sockaddr *)&client, &sockaddr_size);
    	
    	if (new_socket < 0) {
    		perror("accept error");
    		exit(1);
    	}
    	puts("connection accepted");
    	
    	// 发送数据
    	message = "hello world
    ";
    	if (send(new_socket, message, strlen(message), 0) < 0) {
    		perror("send message error");
    		return 1;
    	}
    	puts("send message success");
    
    	if (recv(new_socket, get_recv, 2000, 0) < 0) {
    		perror("recv error");
    		return 2;
    	}
    	puts("recv success");
    	puts(get_recv);
    	
    	// 关闭
    	close(new_socket);
    	close(socket_desc);
    	return 0;
    }
    
    

    到目前为止,server端的主要操作都已经完成,接下来便是对server端的深入处理,使得server端能够一直不断的接受处理连接请求。

  • 相关阅读:
    excel打印预览后整个表格中按页显示虚线,打印时就会打印很多页
    4.8 自定义下拉菜单模式Spinner与setDropDownViewResource
    1.2Matlab基本语法和基本操作.
    CTime类的一个BUG
    【转载】PE_Info 之DIY
    ubuntu使用记录
    反VM测试成功
    获取MAC地址
    【转载】秒到oep,支持所有壳,包括vmp
    【转载】Make your owner PE Protector
  • 原文地址:https://www.cnblogs.com/tingyugetc/p/6256565.html
Copyright © 2011-2022 走看看