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.
时间: 2024-10-28 12:47:23

socket programming example的相关文章

linux c socket programming

原文:linux c socket programming http://54min.com/post/http-client-examples-using-c.html 好文章   PPT http://www.slideshare.net/Arbow/asynchronous-io-programming verygood   C: Linux Socket Programming, TCP, a simple HTTP client http://coding.debuntu.org/c-

急急急,請使用socket programming 抓取另網站上的*.csv資料

问题描述 急急急,請使用socketprogramming抓取另網站上的*.csv資料顯示到網頁上,請高手解決答! 解决方案 解决方案二:不懂,没有用过.不过关注!解决方案三:socket我知道怎么写socketprogramming是啥东西没用过?/*兄弟下次问问题把要问题说清楚一点好不好.大家多半是到csdn闲逛的,专业答题的没几个没人长时间关注一个帖子,等你的帖子沉了就更不可能有人看见了,这样比较浪费你的分还有大家的时间.所以恳请下次发问题的时候一定要描述清楚,因为你心里想的东西不是人人都

Python 的 Socket 编程

 这篇文章最初发布的时候标题是"Python的WebSocket编程",坦白来说有点文不对题.我们在这里打算讨论的仅仅是常规的socket编程.尽管 Web Socket 和常规sockets有点很相似,但又不是同一个东西.那我还是希望这篇文章对你们有点帮助.     Socket是网络应用的基础.而Python使得网络socket编程入门变得超级简单.在这篇简介里面我们将创建一个简单服务器,用于接受和相应客户端程序的请求. 由于本人最近对 Linux Containers 有点痴迷,

socket编程:SO_REUSEADDR例解

socket编程:SO_REUSEADDR例解                                              kevintz 2000-6-19      网友vmstat多次提出了这个问题:SO_REUSEADDR有什么用处和怎么使用.而且很多网友在编写网络程序时也会遇到这个问题.所以特意写了这么一篇文章,希望能够解答一些人的疑难.     其实这个问题在Richard Stevens的<Unix网络编程指南>卷一里有很详细的解答(中文版P166-168页).这里

Python 的 Socket 编程_python

Socket是网络应用的基础.而Python使得网络socket编程入门变得超级简单.在这篇简介里面我们将创建一个简单服务器,用于接受和相应客户端程序的请求. 由于本人最近对 Linux Containers 有点痴迷,因此我们也将在服务器中实现2个容器.同时在容器中我们在几秒钟内就能创建其他一些主机,这就能非常简单的模拟出一个网络. 创建容器 我使用的是Ubuntu14.04. 然后用root用户运行下面的命令就可以创建好2个容器了. 复制代码 代码如下: lxc-create -t down

c语言-TCP/IP socket编程(in c) 美国多纳霍这本书中。

问题描述 TCP/IP socket编程(in c) 美国多纳霍这本书中. 他开始的practial.h是什么呀?http://ask.csdn.net/# 解决方案 http://cs.ecs.baylor.edu/~donahoo/practical/CSockets2/code/code/Practical.h 其他相关源代码:http://cs.ecs.baylor.edu/~donahoo/practical/CSockets2/textcode.html 解决方案二: TCP/IP_

Beginning Winsock Programming - Simple TCP server

Introduction The WinSock (Windows Sockets) API is a socket programming library for Microsoft Windows Operating Systems. It was originally based on Berkeley sockets. But several Microsoft specific changes were employed. In this article I shall attempt

PHP套接字编程

编程 作者:久隆信息/张晓刚 套接字编程,一般使用c或c++.特别的在web应用程序开发中,常用perl实现套接字.除此以外,用php进行套接字编程也是一个选择.Php可以胜任吗?当然可以.Php是一门高质量的web应用程序开发语言,他的许多特性可以处理众多的任务,网络编程也不例外. 1. 理解套接字 Mail.ftp.telnet.name和finger这些服务都是在一个专用的公开的端口上提供的,通过连接到这些端口,客户程序就能够访问这些服务.这与现实生活是相似的--当需要干洗衣服的时候,找干

LinuxC下获取UDP包中的路由目的IP地址和头标识目的地址

在接受到UDP包后,有时候我们需要根据所接收到得UDP包,获取它的路由目的IP地址和头标识目的地址. (一)主要的步骤: 在setsockopt中设置IP_PKTINFO,然后通过recvmsg来获取struct in_pktinfo(struct in_pktinfo是struct msghdr中msg_control的成员).in_pktinfo 结构体(如下所示),我们可以从in_pktinfo中获取路由目的地址(destination address of the packet).头标识