您的位置:首页 > 理论基础 > 计算机网络

linux下socket编程(1)tcp

2014-05-28 22:58 465 查看
-----------------------------------------------------------------------------------------|
(1)TCP服务器步骤
1.创建socket,使用函数socket()
2.绑定IP地址、端口等信息到socket上,使用函数bind()
3.设置允许的最大连接数,使用函数listen()
4.等待来自客户端的连接请求,使用函数accept()
5.用于收发数据,函数send()  recv() or read() write()
6.关闭网络连接
-----------------------------------------------------------------------------------------|
1.1 socket()函数
/*函数说明:socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一通信端口。
成功则返回socket处理代码,失败返回-1。*/
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
//基于socket的tcp 常用
socket(AF_INET,SOCK_STREAM,0)  //TCP VIP4
/*参数domain 指定使用何种的地址类型,完整的定义在/usr/include/bits/socket.h 内,底下是常见的协议*/
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX //进程通信协议
PF_INET?AF_INET                        //Ipv4网络协议
PF_INET6/AF_INET6                      //Ipv6 网络协议
PF_IPX/AF_IPX                          //IPX-Novell协议
PF_NETLINK/AF_NETLINK                  //核心用户接口装置
PF_X25/AF_X25                          //ITU-T X.25/ISO-8208 协议
PF_AX25/AF_AX25                        //业余无线AX.25协议
PF_ATMPVC/AF_ATMPVC                    //存取原始ATM PVCs
PF_APPLETALK/AF_APPLETALK              //appletalk(DDP)协议
PF_PACKET/AF_PACKET                    //初级封包接口
/* 参数type有下列几种数值:*/
SOCK_STREAM                            //提供双向连续且可信赖的数据流,即TCP。支持
OOB                                    //机制,在所有数据传送前必须使用connect()来建立连线状态。
SOCK_DGRAM                             //使用不连续不可信赖的数据包连接
SOCK_SEQPACKET                         //提供连续可信赖的数据包连接
SOCK_RAW                               //提供原始网络协议存取
SOCK_RDM                               //提供可信赖的数据包连接
SOCK_PACKET                            //提供和网络驱动程序直接通信。
protocol                               //用来指定socket所使用的传输协议编号,通常此参考不用管它,
//设为0即可。
/*错误代码*/
EPROTONOSUPPORT          //参数domain指定的类型不支持参数type或protocol指定的协议
ENFILE                   //核心内存不足,无法建立新的socket结构
EMFILE                   //进程文件表溢出,无法再建立新的socket
EACCESS                  //权限不足,无法建立type或protocol指定的协议
ENOBUFS/ENOMEM           //内存不足
EINVAL                   //参数domain/type/protocol不合法
-----------------------------------------------------------------------------------------|
1.2 bind()函数
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
//bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,
//对于不同的socket domain定义了一个通用的数据结构struct sockaddr
{
unsigned short int sa_family;
//sa_family 为调用socket()时的domain参数,即AF_xxxx值。
char sa_data[14]; //sa_data 最多使用14个字符长度。
};
//此sockaddr结构会因使用不同的socket domain而有不同结构定义,例如使用AF_INET domain,
//其socketaddr结构定义便为
struct socketaddr_in
{
unsigned short int sin_family; //sin_family 即为sa_family
uint16_t sin_port;             //sin_port 为使用的port编号
struct in_addr sin_addr;       //sin_addr.s_addr 为IP 地址
unsigned char sin_zero[8];     //无意义,仅仅是为了与sockaddr结构在内存上对齐
};
struct in_addr
{
uint32_t s_addr;               //存放IP地址,需要将主机数据类型转换为网络数据类型
};                             //例:htonl(INADDR_ANY); inet_addr("192.168.1.1");
-----------------------------------------------------------------------------------------|
1.3 listen()函数
#include<sys/socket.h>
int listen(int s,int backlog);
//listen()用来等待参数s 的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此
//上限则client端将收到ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模
//式,真正接收client端连线的是accept()。通常listen()会在socket(),bind()之后调用,再调用accept()。
//如果socket为AF_INET则参数backlog 最大值可设至128。
//例如:listen(sockfd,5);
-----------------------------------------------------------------------------------------|
1.4 accept()函数
#include<sys/types.h>
#include<sys/socket.h>
int accept(int s,struct sockaddr * addr,int * addrlen);
/*
参数s的socket必需先经bind()、listen()函数处理过,当有连线进来时accept()会返回一个新的socket
处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()
来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的地址数据,参数addrlen
为scokaddr的结构长度
*/
-----------------------------------------------------------------------------------------|
1.5 read() write()函数
#include<unistd.h>
ssize_t write (int fd,const voidvoid * buf,size_t  count);
ssize_t read(int fd,voidvoid * buf ,size_t count);

1.6 close()函数
int close(int fd);

(2)实例代码
2.1循环服务器 一次只能处理一个客户端
-----------------------------------------------------------------------------------------|
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define portnumber 3333

int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
int nbytes;
char buffer[1024];

/*1.1socket() 服务器端开始建立sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:IPV4;SOCK_STREAM:TCP
{
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit(1);
}
-----------------------------------------------------------------------------------------|
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in)); // 初始化,置0
server_addr.sin_family=AF_INET;                 // Internet
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
// (将本机器上的long数据转化为网络上的long数据)和任何主机通信
//INADDR_ANY 表示可以接收任意IP地址的数据,即绑定到所有的IP
//server_addr.sin_addr.s_addr=inet_addr("192.168.1.1");
//用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ip
server_addr.sin_port=htons(portnumber);
// (将本机器上的short数据转化为网络上的short数据)端口号
-----------------------------------------------------------------------------------------|
/*1.2bind() 捆绑sockfd描述符到IP地址 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
exit(1);
}
-----------------------------------------------------------------------------------------|
/* 设置允许连接的最大客户端数 */
if(listen(sockfd,5)==-1)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
exit(1);
}

while(1)
{
-----------------------------------------------------------------------------------------|
/* 1.4 accpet服务器阻塞,直到客户程序建立连接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
// 将网络地址转换成.字符串
-----------------------------------------------------------------------------------------|
/*1.5 read()*/
if((nbytes=read(new_fd,buffer,1024))==-1)
{
fprintf(stderr,"Read Error:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("Server received %s\n",buffer);

/*1.6 close() 这个通讯已经结束 */
close(new_fd);
/* 循环下一个 */
}

/* 结束通讯 */
close(sockfd);
exit(0);
}
2.1并发服务器 一次能处理多个客户端
-----------------------------------------------------------------------------------------|
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: