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

server                                                  client

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

创建socket                                          创建socket

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

|                                                         |

|                                                         |

|                                                         |

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

地址赋值(                                           地址赋值(

自己的地址)                                        服务器地址)

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

|                                                         |

|                                                         |

|                                                         |

++++++++                                              |

用bind绑定                                                |

socket和地址                                             |

++++++++                                              |

|                                                         |

|                                                         |

|                                                         |

+++++++                                                 |

listen                                                         |

+++++++                                                  |

|                                                    ++++++++++

|   <------------------------------          connect 服务器

|                                                    ++++++++++

+++++++                                                  |

accept                                                        |

+++++++                                                  |

|                                                           |

|                                                    +++++++++

|                                                     recv 和send

|                                                     进行数据处理

|                                                     +++++++++

+++++++++                                                |

用accept得到                                                 |

的socket进行                                                 |

recv 和 send                                                 |

+++++++++                                                |

|                                                             |

|                                                             |

|                                                             |

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

close socket                                         close socket

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

根据以上步骤,服务器端的代码为

#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 = ;
int app_sock = ;
struct sockaddr_in hostaddr;
struct sockaddr_in clientaddr;
int socklen = sizeof(clientaddr);
char sendbuf[SEND_BUF_SIZE] = {};
char recvbuf[RECV_BUF_SIZE] = {};
int sendlen = ;
int recvlen = ;
int retlen = ;
int leftlen = ;
char *ptr = NULL;
memset((void *)&hostaddr, , sizeof(hostaddr));
memset((void *)&clientaddr, , 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, );
if(listen_sock < )
{
syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
exit();
}
if(bind(listen_sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) < )
{
syslog(LOG_ERR, "%s:%d, bind socket failed", __FILE__, __LINE__);
exit();
}
if(listen(listen_sock, MAX_LISTEN_NUM) < )
{
syslog(LOG_ERR, "%s:%d, listen failed", __FILE__, __LINE__);
exit();
}
while()
{
app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr, &socklen);
if(app_sock < )
{
syslog(LOG_ERR, "%s:%d, accept failed", __FILE__, __LINE__);
exit();
}
sprintf(sendbuf, "welcome %s:%d here!/n", inet_ntoa(clientaddr.sin_addr.s_addr), clientaddr.sin_port);
//send data
sendlen = strlen(sendbuf) +;
retlen = ;
leftlen = sendlen;
ptr = sendbuf;
//while(leftlen)
{
retlen = send(app_sock, ptr, sendlen, );
if(retlen < )
{
if(errno == EINTR)
retlen = ;
else
exit();
}
leftlen -= retlen;
ptr += retlen;
}
//receive data
recvlen = ;
retlen = ;
ptr = recvbuf;
leftlen = RECV_BUF_SIZE -;
//do
{
retlen = recv(app_sock, ptr, leftlen, ) ;
if(retlen < )
{
if(errno == EINTR)
retlen = ;
else
exit();
}
recvlen += retlen;
leftlen -= retlen;
ptr += retlen;
}
//while(recvlen && leftlen);
printf("receive data is : %s", recvbuf);
close(app_sock);
}
close(listen_sock); return ; }

客户端代码为:

#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 = ;
char recvbuf[RECV_BUF_SIZE] = {};
char sendbuf[SEND_BUF_SIZE] = {};
int recvlen = ;
int retlen = ;
int sendlen = ;
int leftlen = ;
char *ptr = NULL;
struct sockaddr_in ser_addr; memset(&ser_addr, , 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, );
if(sock_fd < )
{
syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);
exit();
}
if(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < )
{
syslog(LOG_ERR, "%s:%d, connect socket failed", __FILE__, __LINE__);
exit();
}
//receive data
recvlen = ;
retlen = ;
ptr = recvbuf;
leftlen = RECV_BUF_SIZE -;
//do
{
retlen = recv(sock_fd, ptr, leftlen, ) ;
if(retlen < )
{
if(errno == EINTR)
retlen = ;
else
exit();
}
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) +;
retlen = ;
leftlen = sendlen;
ptr = sendbuf;
// while(leftlen)
{
retlen = send(sock_fd, ptr, sendlen, );
if(retlen < )
{
if(errno == EINTR)
retlen = ;
else
exit();
}
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[]; /* 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[]; /* protocol-specific address */
};
IPv6的socket地址为struct sockaddr_in6

struct in6_addr {
uint8_t s6_addr[]; /* 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 );  

FROM: http://blog.csdn.net/wind19/article/details/6156339

socket编程——一个简单的例子的更多相关文章

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

    从一个简单的使用TCP样例開始socket编程,其基本过程例如以下: server                                                  client ++ ...

  2. socket计划——一个简单的例子

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

  3. socket编程---一个简单例子

    服务器端代码(单线程): import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamRe ...

  4. ? 原创: 铲子哥 搜狗测试 今天 shell编程的时候,往往不会把所有功能都写在一个脚本中,这样不太好维护,需要多个脚本文件协同工作。那么问题来了,在一个脚本中怎么调用其他的脚本呢?有三种方式,分别是fork、source和exec。 1. fork 即通过sh 脚本名进行执行脚本的方式。下面通过一个简单的例子来讲解下它的特性。 创建father.sh,内容如下: #!/bin/bas

    ? 原创: 铲子哥 搜狗测试 今天 shell编程的时候,往往不会把所有功能都写在一个脚本中,这样不太好维护,需要多个脚本文件协同工作.那么问题来了,在一个脚本中怎么调用其他的脚本呢?有三种方式,分别 ...

  5. socket编程,简单多线程服务端测试程序

    socket编程,简单多线程服务端测试程序 前些天重温了MSDN关于socket编程的WSAStartup.WSACleanup.socket.closesocket.bind.listen.acce ...

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

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

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

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

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

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

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

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

随机推荐

  1. XAF-UI元素概述

    XAF框架会根据业务模型自动生成默认的UI.一般来说,您可以使用默认的用户界面,但如果它不符合您的要求,您可以自定义它.要做到这一点,你应该知道UI是由哪些元素组成的,以及你可以自定义什么元素,以实现 ...

  2. java基础练习 10

    import java.util.Scanner; public class Tenth { /*有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数*/ public stati ...

  3. springmvc+mybatis+spring 整合 SSM

    A 调用摄像头拍照,自定义裁剪编辑头像 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技 ...

  4. ThinkPhp 源码阅读心得

    php 中header 函数 我可能见多了,只要用来跳转.今天在阅读TP源码的时候发现,header函数有第三个参数.有些困惑所以找到手册查阅下,发现 void header ( string $st ...

  5. Perception(1.2)

    4.1.2 Definition of Coordinate Systems The global coordinate system is described by its origin lying ...

  6. 《Dynamic Topic Detection and Tracking: A Comparison of HDP, C-Word, and Cocitation Methods》笔记

    原文地址:http://onlinelibrary.wiley.com/doi/10.1002/asi.23134/abstract 黄色背景是我认为比较重要的,红色字体是我自己的话. 动态主题监测与 ...

  7. Apache server for win解压版的安装与配置

    下载地址: Apache 2.4.16 Win64位:VC14:http://www.apachelounge.com/download/VC14/binaries/httpd-2.4.16-win6 ...

  8. 开通域名绑定DDNS

    一.初衷 我想要有一个自己的域名,然后有自己的server,在server上搭一个网站或者开通一个ftp服务,我想通过这个域名来访问它. 二.什么是DDNS DDNS 动态dns,电信宽带采用拨号联网 ...

  9. AxonVR:体验有触觉有温度的VR世界

    提到VR,通常指的是 Oculus Rift 及 HTC Vive的头盔:它们以视觉及听觉使你感到身处虚拟世界.头盔成功的在视觉及听觉感官上蒙骗了你,但我们体验现实的感官不仅于此.绝大多数的VR产品忽 ...

  10. Openjudge-NOI题库-蛇形填充数组

    题目描述 Description 用数字1,2,3,4,...,n*n这n2个数蛇形填充规模为n*n的方阵. 蛇形填充方法为: 对于每一条左下-右上的斜线,从左上到右下依次编号1,2,...,2n-1 ...