Socket网络编程 - xgc94418297的日志 - 网易博客
来源:互联网 发布:网络无internet 编辑:程序博客网 时间:2024/06/02 03:15
网络编程 2009-04-28 19:43:58
2.让套接字成为被动的,使用listen函数可以将套接口由主动修改为被动.
listen函数原型:int listen(int sockfd, int backlog);
第一个参数:sockfd socket套接口描述字
第二个参数:backlog 连接队列的长度
返回值:0,成功;其他,失败;/*功能:sockfd 用于监听的套接口, backlog是监听到的套接口队列长度*/
3.等待连接的到来,使用accept函数从连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待(这个函数是阻塞的).
accept函数原型:int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
第一个参数:sockfd socket套接口描述字
第二个参数:cliaddr 客户端地址
第三个参数:addrlen 客户端地址结构体长度
返回值:已连接的套接口(代表当前连接). /*功能:用于监听的套接口sockfd, 接收到客户套接口地址的地址结构,指向接受套接口地址缓存最大长度的指针的addrlen. accept()返回一个新的套接口描述符,服务器的生产的新的这个套接口就对应一个客户*/
五、做为客户端
客户端要知道服务器的IP地址以及端口号,需要主动跟服务器建立连接,对于TCP协议,连接建立后才可以开始传输数据,使用connect函数建立连接.
connect函数原型:int connect(int sockfd,const struct sockaddr *addr,socklen_t len);
第一个参数:sockfd socket套接口描述字.
第二个参数:addr 服务器地址.
第三个参数:addrlen 服务器地址结构体长度.
返回值:0,成功;其他,错误.
connect函数建立连接后不会产生新的套接口
六、传输数据
当连接建立后,通信的两端便具备两个套接口,可以用read,write函数从这个通信管道读取后写入数据.send()和recv()这两个函数用于面向连接的socket上进行数据传输。
send()函数原型:int send(int sockfd,const void *msg,int len,int flags);
第一个参数:sockfd 你想用来传输数据的socket描述符;
第二个参数:msg 一个指向要发送数据的指针;
第三个参数:Len 以字节为单位的数据的长度;
第四个参数:flags 一般情况下置为0(关于该参数的用法可参照man手册).
返回值:send()函数返回实际上发送出的字节数. 可能会少于你希望发送的数据,在程序中应该将send()的返回值与希望发送的数据字节数进行比较,当send()返回值与len不匹配时,应该对这种情况进行处理. /*功能:将本地的消息送给套接口sockfd */
例子:
char *msg = "Hello!";
int len, bytes_sent;
……
len = strlen(msg);
bytes_sent = send(sockfd, msg,len,0);
……
recv()函数原型:int recv(int sockfd, void *buf,int len,unsigned int flags);
第一个参数:sockfd 是接受数据的socket描述符;
第二个参数:buf 是存放接收数据的缓冲区;
第三个参数:len是缓冲的长度.
第四个参数:Flags也被置为0.
返回值:Recv()返回实际上接收的字节数.当出现错误时,返回-1并置相应的errno值./*功能:将套接口sockfd 发送过来的东西读到buf 中*/
使用close函数关闭套接字,关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包;
服务器关闭socket创建的套接字,导致服务器无法继续接收新的连接,不会影响已经建立的连接.
关闭accept返回的套接字,将导致它所代表的连接被关闭,但不会影响服务器的监听.
客户端用close就是关闭连接.
可以使用shutdown()函数来关闭socket,该函数允许只停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行.
例如可以关闭某socket的写操作而允许继续在该socket上继续接收数据,直至读入所有数据.
shutdown()函数原型:int shutdown(int sockfd,int how);
第一个参数:sockfd 需要关闭的socket描述符.
第二个参数:how 允许shutdown()函数选择以下几种方式
0->不允许继续接收数据
1->不允许继续发送数据
2->不允许继续接收和发送数据
均为允许调用close()函数
返回值:shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno.
例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//=============================================================
// 语法格式: void main(void)
// 实现功能: 主函数,建立一个TCP Echo Server
// 入口参数: 无
// 出口参数: 无
//=============================================================
int main(int argc,char *argv[])
{
char recvbuf[2048]; // 接收缓冲区
int sockfd; // 套接字
struct sockaddr_in servAddr; // 服务器地址结构体
unsigned short port = 8000; // 监听端口
if(argc > 1) // 由参数接收端口
{
port = atoi(argv[1]);
}
printf("TCP Server Started at port %d!\n", port);
/*
unsigned short port = 8000;
定义端口号为8000
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
socket函数创建一个套接字,使用IPv4,TCP协议
要加上一个错误判断,如果socket返回值小于0,就是错误的
*/
sockfd = socket(AF_INET,SOCK_STREAM,0); // 创建TCP套接字
if(sockfd < 0)
{
perror("Invalid socket");
exit(1);
}
/*
// 初始化服务器地址
//bzero(&servAddr, sizeof(servAddr));
//定义了服务器地址结构体,并初始化,bzero相当于memset,将结构体内容清0
*/
bzero(&servAddr,sizeof(servAddr));
/*
//给服务器地址赋值:
//servAddr.sin_family = AF_INET; //IPv4
//servAddr.sin_port = htons(port); //端口号,注意要把port转换为(16位)网络字节序
//servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,用INADDR_ANY指定为任意IP,转换成(32位)网络字节序
*/
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Binding server to port %d\n", port);
/*
bind(sockfd, (struct sockaddr*)&servAddr, sizeof(struct sockaddr))
绑定地址,要把服务器地址强制转换成sockaddr的结构体,同样加错误判断
*/
if(bind(sockfd, (struct sockaddr*)&servAddr, sizeof(struct sockaddr)) != 0)
{
close(sockfd);
perror("binding err!");
exit(1);
}
/*
listen(sockfd, 1)
开始监听,队列大小为1,只允许一个客户端访问,但实际在linux下不起作用\
*/
if(listen(sockfd, 1) != 0)
{
close(sockfd);
perror("listen err!");
exit(1);
}
printf("waiting client...\n");
while(1)
{
/*
char cliIP[INET_ADDRSTRLEN];
定义一个存放客户端IP地址的数组,大小为16
*/
char cliIP[INET_ADDRSTRLEN]; // 用于保存客户端IP地址
size_t recvLen;
/*
struct sockaddr_in cliAddr;
定义了客户端地址结构体
*/
struct sockaddr_in cliAddr; // 用于保存客户端地址
size_t cliAddrLen = sizeof(cliAddr);
// 必须初始化!!!
/*
int connfd = accept(sockfd, (struct sockaddr*)&cliAddr, &cliAddrLen);
客户端连接到服务器,获得一个已经建立的连接connfd,这个就是当前连接,对它进行读写操作
*/
int connfd = accept(sockfd, (struct sockaddr*)&cliAddr, &cliAddrLen);
// 获得一个已经建立的连接
if(connfd < 0)
{
close(sockfd);
perror("accept err!");
exit(1);
}
/*
inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, cliIP, INET_ADDRSTRLEN);
将客户端的IP地址转换成字符串,存放在cliIP中,INET_ADDSTRLEN指定大小为16
*/
inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, cliIP, INET_ADDRSTRLEN);
printf("client ip = %s\n", cliIP);
while((recvLen = read(connfd, recvbuf, 2048)) > 0)
{
write(connfd, recvbuf, recvLen);
}
close(connfd);
printf("client closed!\n");
}
close(sockfd);
return 0;
}
分析:
服务器:
unsigned short port = 8000;
定义端口号为8000
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
socket函数创建一个套接字,使用IPv4,TCP协议
要加上一个错误判断,如果socket返回值小于0,就是错误的
struct sockaddr_in servAddr;
bzero(&servAddr, sizeof(servAddr));
定义了服务器地址结构体,并初始化,bzero相当于memset,将结构体内容清0
给服务器地址赋值:
servAddr.sin_family = AF_INET; //IPv4
servAddr.sin_port = htons(port); //端口号,注意要把port转换为(16位)网络字节序
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,用INADDR_ANY指定为任意IP,转换成(32位)网络字节序
bind(sockfd, (struct sockaddr*)&servAddr, sizeof(struct sockaddr))
绑定地址,要把服务器地址强制转换成sockaddr的结构体,同样加错误判断
listen(sockfd, 1)
开始监听,队列大小为1,只允许一个客户端访问,但实际在linux下不起作用
客户端:
char cliIP[INET_ADDRSTRLEN];
定义一个存放客户端IP地址的数组,大小为16
struct sockaddr_in cliAddr;
定义了客户端地址结构体
int connfd
connfd = accept(sockfd, (struct sockaddr*)&cliAddr, &cliAddrLen);
客户端连接到服务器,获得一个已经建立的连接connfd,这个就是当前连接,对它进行读写操作
inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, cliIP, INET_ADDRSTRLEN);
将客户端的IP地址转换成字符串,存放在cliIP中,INET_ADDSTRLEN指定大小为16
到这为止,连接已经建立完成,运行程序,用telnet登录服务器,输入服务器IP和端口号,连接成功,
就可以用read,write,读写connfd,实现通信。
- Socket网络编程 - xgc94418297的日志 - 网易博客
- vivi的Makefile分析 - xgc94418297的日志 - 网易博客
- vivi源码分析 - xgc94418297的日志 - 网易博客
- vivi源码分析 - xgc94418297的日志 - 网易博客
- vivi源码分析 - xgc94418297的日志 - 网易博客
- 向vivi中加入命令 - xgc94418297的日志 - 网易博客
- uboot移植文档(一) - xgc94418297的日志 - 网易博客
- uboot在2440上移植(一) - xgc94418297的日志 - 网易博客
- Socket的网络编程
- ToBase64String方法 - 理想的地方的日志 - 网易博客
- FlexGrid合并单元格 - zhengjiazeng的日志 - 网易博客
- FlexGrid合并单元格 - zhengjiazeng的日志 - 网易博客
- ACE的Socket网络编程
- 网络编程的socket基础
- java 的socket网络编程
- Linux的socket网络编程
- socket网络编程的相关内容
- android的SOCKET网络编程
- 架设个人FTP服务器的两类方法
- 跟我一起写makefile
- hibernate错误:object references an unsaved transient instance - save the transient instance
- 堆和栈的区别 (转贴)
- FPGA学习笔记三(比较器)
- Socket网络编程 - xgc94418297的日志 - 网易博客
- (GDB)GDB部分中文手册+gdb_guide.pdf - vim+gcc+gdb+make - Embedded Engineers
- 什么是堆?什么是栈? - C - CalmArrow
- Linux USB驱动框架分析 - 技术文档 - 安装启动 Linux时代 - 开源、自由、共享 - 中国最大的Linux技术社区
- 黑天鹅、
- 中国 WebLogic User Group 2011年北京第二次线下活动
- 嵌入式系统 之 Boot Loader (摘自:嵌入式系统 Boot Loader 技术内幕)
- .NET简谈互操作(五:基础知识之提升平台调用性能)
- 让我们用Backbone.js来写一个HelloWorld程序。