linux socket 网址,linux下socket编程

Socket

soket接口是TCP/IP网络的API。网络的socket数据传输是一种特别的I/O,socket也是一种文档描述符。利用socket()函数打开,返回一个整型的socket描述符,而后创建链接,数据传输等等。经常使用的socket类型有:流式socket(SOCK_STREAM)、数据报socket(SOCK_DGRAM). 其中流式socket是采用面向链接的TCP服务,而数据报socket则是无链接的UDP服务

服务器

Socket创建

调用: int socket(int domain, int type, int prococol)来建立socket网络

domain:指明所使用的协议族,经常使用PF_INET, 表示互联网协议族(TCP/IP)数据结构

说明:dom

在绑定本地地址或链接远程地址时须要初始化sockaddr_in结构,其中指定address family时通常设置为AF_INET,即便用IP。socket

相关头文件中的定义:AF = Address Family

PF = Protocol Family

AF_INET = PF_INETtcp

所以,通常规范的用法是在socket中用PF_INET指定协议族,在设置address中时,使用AF_NET,固然二者是同样的。函数

type:指定socket的类型,分为:SOCK_STREAM(TCP)、SOCK_DGRAM(UDP),SOCK_RAW(原始socket,容许socket调用底层协议)ui

protocol:一般赋值为0spa

socket描述符是一个指向内部数据结构的指针,执行描述符表的入口指针

两个网络程式之间的一个网络链接包括:通讯协议、本地协议地址、本地主机端口、远端主机地址、远端协议端口

socket配置

面向链接的socket客户端经过调用connet函数在socket数据接口中保存本地和远端信息,无链接socket的客户端和服务端联通面向链接socket的服务端经过调用bind函数来配置本地信息

1. int bind(int sockefd, struct sockaddr *my_addr, int addrlen);

struct sockaddr

{

unsigned short sa_family; // 地址族, AF_INET...

char sa_data[14]; // 14字节的协议地址

}

说明,其中sa_family通常为AF_INET,表明tcp/ip协议族,sa_data则包含该socket的IP地址和端口号

struct sockaddr_in

{

short int sin_family; // 地址族

unsigned short int sin_port; // 端口号

struct in_addr sin_addr; // ip地址

unsigned char sin_zero[8]; // 填充0以保证和struct sockaddr一样大小

}

第二个结构体更经常使用,用bzero()或memset()函数将其该结构体置为零

指向sockaddr_in的指针和指向sockaddr的指针可以相互转换

my_addr.sin_port = 0; // 表示随机获取一个没有被占用的端口号

my_addr.sin_addr.s_addr = INADDR_ANY; // 自动填入本机IP地址

my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 客户端的填充IP方式

bind函数须要将sin_port和sin_addr转换成为网络字节有限顺序,而sin_addr则无需转换

internet上数据以高位优先 顺序传输,故须要实现进行转换

htonl(); 把32位值从主机字节序转换为网络字节序

htons(); 把16位值从主机字节序转换为网络字节序

ntohl(); 把32位值从网络字节序转换为主机字节序

ntohs(); 把16位值从网络字节序转换为主机字节序

bind函数在成功调用后,返回0,出错返回-1并将errno设置为响应的错误号

创建链接

面向链接的客户程式使用connet函数来配置socket并和远端服务器创建一个TCP链接

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

sockfd是socket函数返回的socket描述符

serv_addr: 包含远端主机ip地址和端口号的指针

addrlen: 为远端地址结构的长度, sizeof(sockaddr)

connect函数只用于面向链接的客户端程式,无链接和面向链接的服务器不须要,成功则返回0,失败返回-1

listen函数使socket处于被动的监听模式,并为该socket模式创建一个输入数据队列,将到达的服务请求保存在队列中

int listen(int sockfd,int backlog)

sockfd:为socket描述符

backlog: 自定在请求队列中容许的最大请求数

accept函数让服务器接受客户的链接请求,在创建好输入队列后,服务器调用accept函数,而后睡眠并等待客户端的链接唤醒

int accept(int sockfd, void *addr, int *addrlen)

sockfd:是被监听的socked秒速富

addr:一般是个指向sockaddr_in变量的指针,该变量用来存放提出链接请求服务的主机信息;

addrlen:一般是一个指向值为sizeof(struct sockaddr_in)的整型指针变量

当accept函数监控的socket收到链接请求时,socket执行体将创建一个新的socket,执行体将这个新socket和请求链接进程的地址联系起来,收到服务请求的初始socket仍可以继续在之前的socket上监听,同时可以在新的socket描述符上进行数据传输操做

数据传输

send和recv用于面向链接的socket上进行数据传输

int send(int sockfd, const void *msg, int len, int flags)

sockfd: 是想用来传输数据的socket描述符

msg: 指向要发送数据的指针

len:以直接为单位的数据长度

flags:通常设置为0

返回实际上发送出的字节数,可能会少于但愿发送的数据;在程序中应该将send发送的数据和len进行比较,若不匹配时,应该进行处理

char *msg = "hello world";

int len = strlen(msg), bytes_sent;

bytes_sent = send(sockfd, msg, len, 0);

if(bytes_sent != len)

{

....

}

int recv(int sockfd, void *buf, int len, unsigned int flags);

sockfd:接受数据的socket描述符

buf:为存放接受数据的缓冲区

len:缓冲区的长度

flags:通常也被设置为0

返回实际接受的数据字节数

面向无链接的数据socket以sendto()和recvfrom()来进行数据传输

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen)

to表示目地机的IP地址和端口号信息,而tolen常为sizeof(to)

int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from , int *fromlen);

from是sockaddr结构的变量,保存源机的IP地址和端口号,fromlen指向sizeof (struct sockaddr)的变量

结束传输

close(sockfd);

实例代码:

server.c

/*

* server.c

*

*  Created on: 2014-8-29

*      Author: wzb

*/

#include "server.h"

#define temp_pathname "temp.d"

void server_process(int sockfd)

{

char buffer[1024];

int data_len = 0;

FILE *f;

if((f = fopen(temp_pathname, "w")) == NULL)

{

fprintf(stderr, "crete temp file %s error\n", temp_pathname);

exit(1);

}

while((data_len = recv(sockfd, buffer, 1024, 0)) >0)

{

if(data_len 

buffer[data_len] = '\0';

fprintf(f, "%s", buffer);

}

fclose(f);

}

int main()

{

int sockfd;

int clientfd;

uint16_t port = 10033;

struct sockaddr_in server_addr, client_addr;

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr  = htonl(INADDR_ANY);

server_addr.sin_port = htons(port);

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) 

{

fprintf(stderr, "open data stream socket failed!\n");

exit(1);

}

if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) 

{

fprintf(stderr, "bind data socket failed!\n");

exit(1);

}

if(listen(sockfd, SOMAXCONN) 

{

fprintf(stderr, "listen data stream failed\n");

exit(1);

}

while(1)

{

socklen_t len = sizeof(client_addr);

clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &len);

if(clientfd 

{

fprintf(stderr, "accept error\n");

continue;

}

int pid = fork();

if(pid == 0)

{

server_process(clientfd);

exit(0);

}

close(clientfd);

}

return 0;

}

client.c

/*

* client.c

*

*  Created on: 2014-8-29

*      Author: wzb

*/

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define filename "file.d"

int main()

{

int sockfd;

struct sockaddr_in server_addr;

uint16_t port = 10033;

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) 

{

fprintf(stderr, "socket eerror\n");

exit(1);

}

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(port);

server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");;

if(connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr))<0)

{

fprintf(stderr, "connect eerror\n");

return -1;

}

FILE *f = NULL;

if((f = fopen(filename, "r")) == NULL)

{

fprintf(stderr, "%s file error\n", filename);

close(sockfd);

exit(1);

}

char buf[LINE_MAX];

while(fgets(buf, LINE_MAX, f))

{

send(sockfd, buf, strlen(buf), 0);

}

fclose(f);

printf("-----------send over------------\n");

close(sockfd);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值