socket programming example

简介:
1. 头文件
vi server.h 
// 头文件
// 注册信号处理函数
int catch_signal(int sig, void (*handler) (int));
// 从socket读数据到char *buf
int read_in(int socket, char *buf, int len);
// 错误函数, 当exit_val=0只输出错误信息, 不退出程序. 其他值输出错误信息并退出程序
void error(char * msg, int exit_val);
// 创建监听socket
int open_listener_socket();
// 绑定socket到端口port
void bind_to_port(int socket, int port);
// 监听socket, 允许队列数queue.
void listen_to_socket(int socket, int queue);
// 开始等待客户端连接.
int accept_socket(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// 向socket发送信息
int say(int socket, char *s);
// 信号处理函数
void handle_shutdown(int sig);


2. c文件
vi server.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include "server.h"

int catch_signal(int sig, void (*handler) (int)) {
  struct sigaction action;
  action.sa_handler = handler;
  sigemptyset(&action.sa_mask);
  // sigemptyset() return 0 on success and -1 on error.
  action.sa_flags = 0;
  return sigaction(sig, &action, NULL);
  // sigaction() returns 0 on success and -1 on error.
}

// recv()注意:
// 1. The characters are not terminated with a \0 character.
// 2. When someone types text in telnet, the string always ends \r\n.
// 3. The recv() will return the number of characters, or –1 if there's an error, or 
//    0 if the client has closed the connection.
// 4. You're not guaranteed to receive all the characters in a single call to recv().

// This reads all the characters until it reaches '\n'.
int read_in(int socket, char *buf, int len) {
  char *s = buf;
  int slen = len;
  int c = recv(socket, s, slen, 0);
  // Keep reading until there are no more characters or you reach '\n'.
  while ( (c > 0) && (s[c-1] != '\n') ) {
    s += c; slen -= c;
    c = recv(socket, s, slen, 0);
  }
  if (c < 0)
    // In case there's an error
    return c;
  else if (c == 0)
    // Nothing read; send back an empty string
    buf[0] = '\0';
  else
    // Replace the last character(here is '\n') with a '\0'.
    s[c-1] = '\0';
  return len-slen;
}

void error(char * msg, int exit_val) {
  fprintf(stderr, "%s: %s\n", msg, strerror(errno));
  // if exit_val == 0, not exit the program.
  if (exit_val)
    exit(exit_val);
}

int open_listener_socket() {
  // Create an Internet streaming socket.
  int s = socket(PF_INET, SOCK_STREAM, 0);
  if (s == -1)
    error("Can't open socket", 1);
  return s;
}

void bind_to_port(int socket, int port) {
  struct sockaddr_in name;
  name.sin_family = PF_INET;
  name.sin_port = (in_port_t) htons(port);
  name.sin_addr.s_addr = htonl(INADDR_ANY);
  // Yes, reuse the socket (so you can restart the server without problems).
  int reuse = 1;
  if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(int)) == -1)
    error("Can't set the reuse option on the socket", 1);
  int c = bind(socket, (struct sockaddr *) &name, sizeof(name));
  if(c == -1)
    error("Can't bind to socket", 1);
}

void listen_to_socket(int socket, int queue) {
  int l = listen(socket, queue);
  if(l == -1)
    error("Can't listen", 1);
}

// wait client connect to this server. return the secondary socketfd.
int accept_socket(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
  int connect_d = accept(sockfd, addr, addrlen);
  if (connect_d == -1)
    error("Can't open secondary socket", 1);
  return connect_d;
}

// Send a string to a client.
int say(int socket, char *s) {
  int result = send(socket, s, strlen(s), 0);
  if(result == -1)
    // when error don't exit.
    error("Error talking to the client", 0);
  return result;
}

// This will store the main listener socket for the server.
int listener_d;

// If someone hits Ctrl-C when the server is running, 
// this function will close the socket before the program ends.
void handle_shutdown(int sig) {
  if(listener_d)
    close(listener_d);
  fprintf(stderr, "Signal:%i, Bye!\n", sig);
  exit(0);
}

int main(int argc, char *argv[]) {
  int port;
  int queue;
  char opt;
  // get option argument
  while ((opt = getopt(argc, argv, "hp:q:")) != EOF) {
    switch(opt) {
      case 'h':
        fprintf(stdout, "%s -p $port_num -q $queue_num\n", argv[0]);
        exit(1);
      case 'p':
        port = atoi(optarg);
        break;
      case 'q':
        queue = atoi(optarg);
        break;
      default:
        fprintf(stderr, "Unknown option: %s\n", optarg);
        return 1;
    }
  }
  // if argument count is not 5, exit main function.
  if(argc != 5) {
    fprintf(stdout, "%s -p $port_num -q $queue_num\n", argv[0]);
    return 1;
  }
  // 注册SIGINT 到信号处理函数handle_shutdown.
  if(catch_signal(SIGINT, handle_shutdown) == -1)
    error("Can't set the interrupt handler", 1);
  // 打开一个data stream socket.
  listener_d = open_listener_socket();
  // 绑定到端口port
  bind_to_port(listener_d, port);
  // 监听, 并指定queue长度
  listen_to_socket(listener_d, queue);
  // 准备接收客户端连接
  struct sockaddr_storage client_addr;
  unsigned int address_size = sizeof(client_addr);
  puts("Waiting for connection");
  char buf[255];
  // accept_socket等待客户端连接.
  while(1) {
    // accept将创建the secondary socketfd.
    int connect_d = accept_socket(listener_d, (struct sockaddr *) &client_addr, &address_size);
    // 子进程处理客户端请求
    if ( !fork() ) {
      close(listener_d);
      if (say(connect_d, "Internet Knock-Knock Protocol Server\r\nVersion 1.0\r\nKnock! Knock!\r\n> ") != -1) {
        read_in(connect_d, buf, sizeof(buf));
      }
      if (strncasecmp("Who's there?", buf, 12))
        say(connect_d, "You should say 'Who's there?'!");
      else {
        if (say(connect_d, "Oscar\r\n> ") != -1) {
          read_in(connect_d, buf, sizeof(buf));
          if (strncasecmp("Oscar who?", buf, 10))
            say(connect_d, "You should say 'Oscar who?'!\r\n");
          else
            say(connect_d, "Oscar silly question, you get a silly answer\r\n");
        }
      }
      // 子进程处理完请求后关闭the secondary socketfd. 并退出.
      close(connect_d);
      exit(0);
    }
    // 主进程不与客户端继续交互, 所以直接关闭the secondary socketfd. 继续while循环, 等待客户端连接.
    close(connect_d);
  }
  return 0;
}

2. 编译, 执行.
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -I. -g ./server.c -o server
[root@db-172-16-3-150 zzz]# ./server -h
./server -p $port_num -q $queue_num
[root@db-172-16-3-150 zzz]# ./server -p 30000 -q 10  // 因为本例用子进程处理客户端请求, 主进程及时的close(connect_d), 所以这个queue不需要太大. 0就可以了.
Waiting for connection


其他会话1 : 
[root@db-172-16-3-150 zzz]# telnet 172.16.3.150 30000
Trying 172.16.3.150...
Connected to db-172-16-3-150.sky-mobi.com (172.16.3.150).
Escape character is '^]'.
Internet Knock-Knock Protocol Server
Version 1.0
Knock! Knock!
> hello
You should say 'Who's there?'!Connection closed by foreign host.


其他会话2 : 
[root@db-172-16-3-150 zzz]# telnet 172.16.3.150 30000
Trying 172.16.3.150...
Connected to db-172-16-3-150.sky-mobi.com (172.16.3.150).
Escape character is '^]'.
Internet Knock-Knock Protocol Server
Version 1.0
Knock! Knock!
> Who's there?
Oscar
> Oscar who?
Oscar silly question, you get a silly answer
Connection closed by foreign host.


【注意】
1. NAME
       listen - listen for connections on a socket

SYNOPSIS
       #include <sys/socket.h>

       int listen(int sockfd, int backlog);
NOTES
       The  behaviour  of  the  backlog  parameter  on TCP sockets changed with Linux 2.2.  Now it specifies the queue
       length for completely established sockets waiting to be accepted, instead of the number of  incomplete  connec-
       tion  requests. The maximum length of the queue for incomplete sockets can be set using the tcp_max_syn_backlog
       sysctl.  When syncookies are enabled there is no logical maximum length and this  sysctl  setting  is  ignored.
       See tcp(7) for more information.

目录
相关文章
|
机器学习/深度学习 C语言
|
网络协议 Unix Linux
linux c socket programming
原文:linux c socket programming http://54min.com/post/http-client-examples-using-c.html 好文章   PPT http://www.
1154 0
|
Java
Java Socket Example
1.服务端:server package com.socket; import java.io.BufferedReader; import java.io.IOException; import java.
935 0
|
网络协议 Shell Python
Bash socket programming with /dev/tcp(大家能联想到怎么使用吗)
http://pangty.ta139.com/bash-guide/abs3.7cnhtm/devproc.
921 0
|
12月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
116 0
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
168 4
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
【7月更文挑战第25天】在网络应用蓬勃发展的数字时代,Python凭借其简洁的语法和强大的库支持成为开发高效应用的首选。本文通过实时聊天室案例,介绍了Python Socket编程的基础与进阶技巧,包括服务器与客户端的建立、数据交换等基础篇内容,以及使用多线程和异步IO提升性能的进阶篇。基础示例展示了服务器端监听连接请求、接收转发消息,客户端连接服务器并收发消息的过程。进阶部分讨论了如何利用Python的`threading`模块和`asyncio`库来处理多客户端连接,提高应用的并发处理能力和响应速度。掌握这些技能,能使开发者在网络编程领域更加游刃有余,构建出高性能的应用程序。
115 3
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
166 2
|
消息中间件 网络协议 网络安全
Python Socket编程:打造你的专属网络通道,基础篇与进阶篇一网打尽!
【7月更文挑战第26天】在网络编程领域,Python以简洁语法和强大库支持成为构建应用的首选。Socket编程为核心,实现计算机间的数据交换。
166 1