从一个简单易用TCP样品开始socket计划,的基本过程例如下列:

server                                                  client

+++++++                                          ++++++++

创建socket                                          创建socket

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

+++++++                                          ++++++++

地址赋值(                                           地址赋值(

自己的地址)                                        server地址)

+++++++                                          ++++++++

|                                                         |

|                                                         |

|                                                         |

++++++++                                              |

用bind绑定                                                |

socket和地址                                             |

++++++++                                              |

|                                                         |

|                                                         |

|                                                         |

+++++++                                                 |

listen                                                         |

+++++++                                                  |

|                                                    ++++++++++

|   <------------------------------          connect server

|                                                    ++++++++++

+++++++                                                  |

accept                                                        |

+++++++                                                  |

|                                                           |

|                                                    +++++++++

|                                                     recv 和send

|                                                     进行数据处理

|                                                     +++++++++

+++++++++                                                |

用accept得到                                                 |

的socket进行                                                 |

recv 和 send                                                 |

+++++++++                                                |

|                                                             |

|                                                             |

|                                                             |

+++++++++                                        +++++++++

close socket                                         close socket

+++++++++                                        +++++++++

依据以上步骤,server端的代码为

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#define MAX_LISTEN_NUM 5
#define SEND_BUF_SIZE 100
#define RECV_BUF_SIZE 100
#define LISTEN_PORT 1010
int main()
{
int listen_sock = 0;
int app_sock = 0;
struct sockaddr_in hostaddr;
struct sockaddr_in clientaddr;
int socklen = sizeof(clientaddr);
char sendbuf[SEND_BUF_SIZE] = {0};
char recvbuf[RECV_BUF_SIZE] = {0};
int sendlen = 0;
int recvlen = 0;
int retlen = 0;
int leftlen = 0;
char *ptr = NULL;
memset((void *)&hostaddr, 0, sizeof(hostaddr));
memset((void *)&clientaddr, 0, sizeof(clientaddr));
hostaddr.sin_family = AF_INET;
hostaddr.sin_port = htons(LISTEN_PORT);
hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if(listen_sock < 0)
{
syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
exit(1);
}
if(bind(listen_sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) < 0)
{
syslog(LOG_ERR, "%s:%d, bind socket failed", __FILE__, __LINE__);
exit(1);
}
if(listen(listen_sock, MAX_LISTEN_NUM) < 0)
{
syslog(LOG_ERR, "%s:%d, listen failed", __FILE__, __LINE__);
exit(1);
}
while(1)
{
app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr, &socklen);
if(app_sock < 0)
{
syslog(LOG_ERR, "%s:%d, accept failed", __FILE__, __LINE__);
exit(1);
}
sprintf(sendbuf, "welcome %s:%d here!/n", inet_ntoa(clientaddr.sin_addr.s_addr), clientaddr.sin_port);
//send data
sendlen = strlen(sendbuf) +1;
retlen = 0;
leftlen = sendlen;
ptr = sendbuf;
//while(leftlen)
{
retlen = send(app_sock, ptr, sendlen, 0);
if(retlen < 0)
{
if(errno == EINTR)
retlen = 0;
else
exit(1);
}
leftlen -= retlen;
ptr += retlen;
}
//receive data
recvlen = 0;
retlen = 0;
ptr = recvbuf;
leftlen = RECV_BUF_SIZE -1;
//do
{
retlen = recv(app_sock, ptr, leftlen, 0) ;
if(retlen < 0)
{
if(errno == EINTR)
retlen = 0;
else
exit(1);
}
recvlen += retlen;
leftlen -= retlen;
ptr += retlen;
}
//while(recvlen && leftlen);
printf("receive data is : %s", recvbuf);
close(app_sock);
}
close(listen_sock);

return 0;

}

client代码为:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#include <errno.h>
#include <stdlib.h>
#define MAX_LISTEN_NUM 5
#define SEND_BUF_SIZE 100
#define RECV_BUF_SIZE 100
#define SERVER_PORT 1010
int main()
{
int sock_fd = 0;
char recvbuf[RECV_BUF_SIZE] = {0};
char sendbuf[SEND_BUF_SIZE] = {0};
int recvlen = 0;
int retlen = 0;
int sendlen = 0;
int leftlen = 0;
char *ptr = NULL;
struct sockaddr_in ser_addr;

memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
inet_aton("127.0.0.1", (struct in_addr *)&ser_addr.sin_addr);
ser_addr.sin_port = htons(SERVER_PORT);
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(sock_fd < 0)
{
syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
exit(1);
}
if(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)
{
syslog(LOG_ERR, "%s:%d, connect socket failed", __FILE__, __LINE__);
exit(1);
}
//receive data
recvlen = 0;
retlen = 0;
ptr = recvbuf;
leftlen = RECV_BUF_SIZE -1;
//do
{
retlen = recv(sock_fd, ptr, leftlen, 0) ;
if(retlen < 0)
{
if(errno == EINTR)
retlen = 0;
else
exit(1);
}
recvlen += retlen;
leftlen -= retlen;
ptr += retlen;
}
//while(recvlen && leftlen);
printf("receive data is : %s", recvbuf);
sprintf(sendbuf, "hello server/n");
//send data
sendlen = strlen(sendbuf) +1;
retlen = 0;
leftlen = sendlen;
ptr = sendbuf;
// while(leftlen)
{
retlen = send(sock_fd, ptr, sendlen, 0);
if(retlen < 0)
{
if(errno == EINTR)
retlen = 0;
else
exit(1);
}
leftlen -= retlen;
ptr += retlen;
}
close(sock_fd);

}

如今一个简单的使用tcp的socket通信的样例已经完毕了。这里有几个须要说明的问题

1)头文件:

sys/socket.h   包括了socket相关的函数,如socket。send 和recv, 以及struct sockaddr等

netinet/in.h    包括了地址结构。如struct sockaddr_in

errno.h           包括了errno 和 EINTR

syslog.h         包括了syslog相关的信息,其打印结果在/var/log/messages里面

2)socket地址

对于IPv4来说,其地址用的是struct sockaddr_in,详细结构例如以下

struct in_addr {
in_addr_t s_addr; /* 32-bit IPv4 address */
/* network byte ordered */
}; struct sockaddr_in {
uint8_t sin_len; /* length of structure (16) */
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 16-bit TCP or UDP port number */
/* network byte ordered */
struct in_addr sin_addr; /* 32-bit IPv4 address */
/* network byte ordered */
char sin_zero[8]; /* unused */
}; 当中sin_len我们一般不关注。也不填(仅仅有在使用routing socket的时候才用到,被内核用来处理各种协议簇的地址结构)。
bind, connect, sendto, 和 sendmsg会把socket地址从程序传递给内核; 而accept, recvfrom, recvmsg, getpeername, 和 getsockname会把地址从内核传递给程序。由于不同协议簇的地址结构是不一样的。所以必需要有一个通用的指针来传递地址。对于ANSI C来说我们一般使用void *,可是socket产生早于ANSI C。所以也就没有使用这个机制,而是使用一个通用的地址结构struct sockaddr来处理的
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
}; IPv6的socket地址为struct sockaddr_in6 struct in6_addr {
uint8_t s6_addr[16]; /* 128-bit IPv6 address */
/* network byte ordered */
}; #define SIN6_LEN /* required for compile-time tests */ struct sockaddr_in6 {
uint8_t sin6_len; /* length of this struct (28) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* transport layer port# */
/* network byte ordered */
uint32_t sin6_flowinfo; /* flow information, undefined */
struct in6_addr sin6_addr; /* IPv6 address */
/* network byte ordered */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
}; 对于sockaddr-in6来说。我们不能用通用的地址struct sockaddr来存储了,而是产用新的通用地址结构struct sockaddr_storage,这个结构足够大能够存储不论什么系统支持的地址。
struct sockaddr_storage {
uint8_t ss_len; /* length of this struct (implementation dependent) */
sa_family_t ss_family; /* address family: AF_xxx value */
/* implementation-dependent elements to provide:
* a) alignment sufficient to fulfill the alignment requirements of
* all socket address types that the system support
* b) enough storage to hold any type of socket address that the
* system supports.
*/
};

几种常见的地址结构


3) 相关函数的的length
对于从程序传地址给内核的函数(如connect),其长度是一个整型值。告诉内核要copy的地址长度。 对于从内核传递给程序的函数(如accpt)。其长度是一个整型指针。是一个value-result參数。 有两个目的:一告诉内核地址结构的长度。让内核在copy的时候不要超过这个长度;二返回内核真正copy的长度。 4)字节序
socket相关的函数都是使用网络字节序 5)地址转换函数
inet_aton, inet_ntoa, and inet_addr把IPv4字符串地址转为32位的网络字节序地址
inet_ptonand inet_ntop能够转换IPv4和IPv6的地址
6)listen中的backlog
要知道这个值的含义先用说一下。对于一个listen的socket,有两个队列:一个是incomplete connection队列(只收到SYN)。一个是complete connection队列(三次握手完毕)。accept函数就是在complete connection队列中取一个socket。 backlog就是指队列的个数。但不行的是各个地方都没有明白定义这个值,没有说明到底代表了哪个队列,或是两个队列之和。一般来说能够
同一时候处理的连接数是backlog的1.5倍,非常多地方都用5. 7) getsockname 和 getpeername
这两个函数能够与socket关联的地址,getsockname 和 getpeername分别得到自己和对端的地址
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen)

int getpeername(int sockfd , struct sockaddr * peeraddr , socklen_t * addrlen ); 

socket计划——一个简单的例子的更多相关文章

  1. socket编程——一个简单的例子

    从一个简单的使用TCP例子开始socket编程,其基本步骤如下: server                                                  client ++++ ...

  2. Linux内核中的信号机制--一个简单的例子【转】

    本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...

  3. 用一个简单的例子来理解python高阶函数

    ============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...

  4. Spring-Context之一:一个简单的例子

    很久之前就想系统的学习和掌握Spring框架,但是拖了很久都没有行动.现在趁着在外出差杂事不多,就花时间来由浅入深的研究下Spring框架.Spring框架这几年来已经发展成为一个巨无霸产品.从最初的 ...

  5. 关于apriori算法的一个简单的例子

    apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...

  6. 扩展Python模块系列(二)----一个简单的例子

    本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...

  7. fitnesse - 一个简单的例子(slim)

    fitnesse - 一个简单的例子(slim) 2017-09-30 目录1 编写测试代码(Fixture code)2 编写wiki page并运行  2.1 新建wikiPage  2.2 运行 ...

  8. Struts2的配置和一个简单的例子

    Struts2的配置和一个简单的例子 笔记仓库:https://github.com/nnngu/LearningNotes 简介 这篇文章主要讲如何在 IntelliJ IDEA 中使用 Strut ...

  9. 一个简单的例子搞懂ES6之Promise

    ES5中实现异步的常见方式不外乎以下几种: 1. 回调函数 2. 事件驱动 2. 自定义事件(根本上原理同事件驱动相同) 而ES6中的Promise的出现就使得异步变得非常简单.promise中的异步 ...

随机推荐

  1. Eclipse Maven构建Spring MVC项目

    工作中项目开发使用Maven管理项目的构建.打包.编译,框架採用的是Spring MVC框架,而且实现了多模块.多项目的管理.自己也简单的參与了架构的设计.对于刚開始学习的人来说,使用Maven构建项 ...

  2. 使用 Advanced Installer 打包 一键安装Web应用程序

    原文:使用 Advanced Installer 打包 一键安装Web应用程序 安装预览: 资源下载: 示例安装包 操作流程: 1.新建Asp.net Application. 2.设置应用程序名称和 ...

  3. 汉高澳大利亚sinox2014电影播放flash最好的办法是安装游戏windows文本firefox

    事实上,韩澳sinox本身是没有原生flashplayer,无论怎么捣鼓,它们是从adobe弄linux要么windows版本号flashplayer,它不停地拨弄linux版本号flashplaye ...

  4. Android SDCard Mount 流程分析

    前段时间对Android 的SDCard unmount 流程进行了几篇简短的分析,由于当时只是纸上谈兵,没有实际上的跟进,可能会有一些误导人或者小错误.今天重新梳理了头绪,针对mount的流程再重新 ...

  5. 快速入门:十分钟学会Python(转)

    初试牛刀 假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(Cheat ...

  6. 《高性能 JavaScript》读书笔记(一)

    一. 加载和执行——优化JavaScript规则: 1. 将脚本放在底部:2. 减少页面中外链脚本文件的数量: 比如,下载单个100kb的文件将比下载4个25kb的文件更快.这个可以通过离线打包工具或 ...

  7. ashx的学习

    原文:ashx的学习 嘿嘿,今天我们休息,本来是想总结一下前两周学习的javascript和jquery,但是感觉好困哦,就没有认真地学习啦,于是做了一个小小的练习,刚开始学习html使用在项目中还是 ...

  8. javascript系列之执行上下文

    原文:javascript系列之执行上下文 写在前面:一 直想系统的总结一下学过的javascript知识,喜欢这门语言也热爱这门语言.未来想从事前端方面的工作,提前把自己的知识梳理一下.前面写了些 ...

  9. hdu Max Sum Plus Plus(dp+滚动数组)

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 m为段,要深刻理解题意,并没有说是段与段要连接. 题解链接:http://blog.csdn.n ...

  10. JAVA8,SPRING,ANGULARJS对项目

    java8+spring+angularjs 项目应用 最近有写一个电子订单商务网站,使用JAVA8,SPRING,ANGULARJS对项目使用的技术和大家分享. 第一次写博客,哪有不对需要改正的请联 ...