`
BlogDown
  • 浏览: 213381 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

linux + socket

 
阅读更多

linux + socket(server)

/*************************
参 考:[1] google.com
[2] Beginning Linux Programming (Third Edition)
**************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
int main(int argc,char **argv)
{
int sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
unsigned int sin_size,myport,listnum;
myport = 2160;
listnum = 10;
/*************************************************
Socket接口:是TCP/IP网络的API,Socket接口定义了许多的函数,可以
在此基础上开发Internet上的TCP/IP网络编程

Create Socket: int socket(int domain, int type, int protoco);

Argument Description:domain 指明所有协议族,通常是PF_INET(TCP/IPV4)
当然他也可以支持IPV6,和更多的网络协议,根据
具体的应用来选择
type 分SOCK_STREAM(TCP),SOCK_DGRAM(UDP),SOCK_RAW
(允许程序使用底层协议)
protolol 通常赋值“0”

Return Value: Socket描述符是一个指向内部数据结构的指针,它指向描述符表
入口。调用Socket函数时,socket执行体将建立一个Socket,
实际上"建立一个Socket"意味着为一个Socket数据结构分配存
储空间。Socket执行体为你管理描述符表。
**************************************************/
if((sockfd = socket(PF_INET,SOCK_STREAM,0)) == -1 )
{
perror("socket is error/n;");
exit(1);
}
my_addr.sin_family = PF_INET; //指定协议族


/***************************************************
计算机数据存储有两种字节优先顺序:高位字节优先和低
位字节优先。Internet上数据以高位字节优先顺序在网络
上传输,所以对于在内部是以低位字节优先方式存储数据
的机器,在Internet上传输数据时就需要进行转换,否则
就会出现数据不一致。
htonl():把32位值从主机字节序转换成网络字节序
htons():把16位值从主机字节序转换成网络字节序
ntohl():把32位值从网络字节序转换成主机字节序
ntohs():把16位值从网络字节序转换成主机字节序
****************************************************/
my_addr.sin_port = htons(myport); //如果填入0,系统将随机选择一个端口

my_addr.sin_addr.s_addr = INADDR_ANY; //填入本机IP地址
bzero(&(my_addr.sin_zero),0);

/**************************************************
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
Description:创建socket,只是在系统中注册,分得自己得一席空间,
那么bind就是将起申请得空间与自己得程序关联起来
Argument Description: sockfd:是Socket系统调用返回的socket 描述符
my_addr:需要绑定在套接字上的地址,
是类似于以下结构体的变量
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
Return Value: 成功执行时,返回0。失败返回-1,errno被设置出错信息
***************************************************/
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
{
perror("bind is error/n");
exit(1);
}

/**************************************************
通过socket()和bind(),就相当于建立了一个本程的一个
指挥部,但是还要派出侦察兵去打探情况,那就是listen()
int listen(int sockfd, int ListenSum)
Description: Listen()函数使socket处于被动的监听模式,
并为该socket建立一个输入数据队列,将
到达的服务请求保存在此队列中,直到程
序处理它们。
Argument Description:sockfd: 是Socket系统调用返回的socket 描述符
ListenSum: 指定在请求队列中允许的最大请求数
Return Value: 成功执行时,返回0。失败返回-1,errno被设置出错信息
***************************************************/
if(listen(sockfd,listnum) == -1)
{
perror("listen is error/n");
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);

/***********************************************************
通过socket(),listen(),bind(),得到的信息,现在是要
发出应对指令,那就是accept()
int accept(int sockfd, void *addr, int *addrlen)
Description:accept()函数让服务器接收客户的连接请求。
在建立好输入队列后,服务器就调用accept
函数,然后睡眠并等待客户的连接请求。
Argument Description:sockfd: 是Socket系统调用返回的socket 描述符
addr : 通常是一个指向sockaddr_in变量的指针,
该变量用来存放提出连接请求服务的主
机的信息(某台主机从某个端口发出该请求)
addrten: 通常为一个指向值为
sizeof(struct sockaddr_in)的整型指针变量
Return Value: 失败返回-1,errno被设置出错信息
成功返回 当accept函数监视的socket收到连接请求时,
socket执行体将建立一个新的 socket,执
行体将这个新socket和请求连接进程的地址
联系起来,收到服务请求的初始socket仍可
以继续在以前的 socket上监听,同时可以在
新的socket描述符上进行数据传输操作
***************************************************************/
if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)
{
perror("accept is error");
continue;

}
printf("server:got connection from %s/n",inet_ntoa(their_addr.sin_addr));

/**************************************************************************
fork一个子进程对此次连接同父进程并行运行
写到这里想到前不久需要在服务器上运行一个程序300次,当时是用批处理解决的,后
来用syetem(),exec系列函数试图解决未果,用perl也未能解决,知道能用shell脚本
很好的解决,看来需要学一下shell脚本了。
***************************************************************************/
if(!fork())
{

/***********************************************************************
int send(int sockfd, const void *msg, int len, int flags)
Description:通过子进程发送信息给客户端
Argument Description: sockfd: 是你想用来传输数据的socket描述符
msg : 是一个指向要发送数据的指针
Len : 是以字节为单位的数据的长度
flags : 一般情况下置为0(这个参数涉及到阻塞和非阻塞问题)
************************************************************************/
if(send(new_fd,"hello,HuHan/n",14,0) == -1)
{
perror("send is error/n");
close(new_fd);
exit(0);
}
}

/******************************************************************************
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在
该socket上的任何数据操作

如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。

   int shutdown(int sockfd,int how);

  Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:
·0-------不允许继续接收数据
·1-------不允许继续发送数据
·2-------不允许继续发送和接收数据
shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。
*******************************************************************************/
close(new_fd);

/****************************************************************************
pid_t waitpid(pid_t pid, int *stat_loc, int option)
pid参数指定需要等待的子进程的PID,如果是-1,waitpid将返回任一子进程的信息,与
wati()一样,如果stat_loc不是空指针,waitpid将把状态信息写到所指向的位置。option
参数允许我们改变waitpid的行为,其中最有用的一个选项是WNOHANG,他的作用是防止
waitpid()调用将调用者执行挂起,可以用这个选项来查找是否有子进程已经结束,如果没有
将继续执行。
*****************************************************************************/
waitpid(-1,NULL,WNOHANG);
}
}

linux + socket(client)

/****************************************************************
Thank to GOOGLE.COM,人多量力大,写这个程序充分验证这点。

本程序和上个server程序,是近一个星期利用下班时间写的一个关于
linux下的socket通讯的程序,写完这个程序,在论坛上看有人提出
怎么实现linux代理实现http,看来这就是下个目标了。

对于hook(钩子),用VB实现的,写完后有点恶作剧的味道,甚至改进一下
可以做出一个简易的盗号木马,既然是恶作剧,会在下一篇日志中copy
部分学习笔记,代码就免了。

以上是上个星期空余时间所学习的。

本程序在Linux Kernel 2.4.20-8 , gcc-3.2.2.5编译通过.
****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAXDATASIZE 1000

int main(int argc, char *argv[])
{
int sockfd,numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in their_addr;
unsigned int myport;
char *host = "192.168.1.155";
myport = 2160;
if ((sockfd = socket(PF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
their_addr.sin_family = PF_INET;
their_addr.sin_port = htons(myport);

/*****************************************************************************
unsigned long int inet_addr(const char *cp);
Description : inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用
的二进制数字。
Return Value: 成功则返回对应的网络二进制的数字,失败返回-1。
******************************************************************************/
their_addr.sin_addr.s_addr = inet_addr(host);

/******************************************************************************
int connect(int sockfd, struct sockaddr *serv_addr,int addrlen)
Description: 通过socket调用返回一个socket描述符后,在使用socket进行网络传输
以前,必须配置该 socket。面向连接的socket客户端通过调用Connect
函数在socket数据结构中保存本地和远端信息。无连接socket的客户端
和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。
Argument Description: sockfd : 是socket函数返回的socket描述符
serv_addr: 是包含远端主机IP地址和端口号的指针
addrlen : 是远端地质结构的长度
Return Value : 函数在出现错误时返回-1,并且设置errno为相应的错误码
*******************************************************************************/
if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1)
{
perror("connect is error");
}

/****************************************************************************
int recv(int sockfd,void *buf,int len,unsigned int flags)
Argument Description: Sockfd :是接受数据的socket描述符
buf :是存放接收数据的缓冲区
len :是缓冲的长度
flags : 一般情况下置为0(这个参数涉及到阻塞和非阻塞问题)
*****************************************************************************/
if((numbytes = recv(sockfd, buf, MAXDATASIZE,0)) == -1)
{
perror("recv is error");
exit(1);
}
buf[numbytes] = 0;
printf("Received:%s/n",buf);
close(sockfd);
return;
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics