① 设计一个linux c语言,Http协议的服务器,用socket收发消息,简单点,求代码and注释。
OK
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
int sockfd,new_socket;
int sock_value;
char buf[] = "hello! China!I Love You\n";
struct sockaddr_in client_;
struct sockaddr_in server_;
int SIZE = sizeof(struct sockaddr_in);
if(argc != 2){
fprintf(stderr,"The two number!\n");
exit(1);
}
if((sock_value = atoi(argv[1])) < 0){
fprintf(stderr,"socket error!\n");
exit(1);
}
if((sockfd = socket(PF_INET,SOCK_STREAM, 0)) == -1){
perror("socket");
exit(1);
}
bzero(&server_,SIZE);
server_.sin_family = PF_INET;
server_.sin_port = htons(sock_value);
server_.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd,(struct sockaddr *)(&server_),SIZE) == -1){
perror("bind");
exit(1);
}
if(listen(sockfd, 12) == -1){
perror("listen");
exit(1);
}
printf("Waiting ... ...\n");
while(1){
if((new_socket = accept(sockfd,(struct sockaddr *)(&client_),&SIZE)) == -1){
perror("accept");
exit(1);
}
printf("The client IP is %s\n",inet_ntoa(client_.sin_addr));
printf("The socket is %d\n",ntohs(client_.sin_port));
if(write(new_socket,buf,strlen(buf)) == -1){
perror("write");
exit(1);
}
int my;
char mybuf[1024];
if((my = read(new_socket, mybuf,1024)) == -1){
perror("read");
exit(1);
}
mybuf[my] = '\0';
printf("#++++#++++#:%s\n",mybuf);
close(new_socket);
}
close(sockfd);
return 0;
}
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int sockfd;
int sock_value;
char buf[1024];
char mybuf[] = "Linux\n";
int read_count;
struct sockaddr_in client_;
struct sockaddr_in server_;
int SIZE = sizeof(struct sockaddr_in);
if(argc != 3){
fprintf(stderr,"The two number!\n");
exit(1);
}
if((sock_value = atoi(argv[2])) < 0){
fprintf(stderr,"socket error!\n");
exit(1);
}
if((sockfd = socket(PF_INET,SOCK_STREAM, 0)) == -1){
perror("socket");
exit(1);
}
bzero(&client_,SIZE);
bzero(&server_,SIZE);
client_.sin_family = PF_INET;
client_.sin_port = htons(52252);
client_.sin_addr.s_addr = INADDR_ANY;
server_.sin_family = PF_INET;
server_.sin_port = htons(sock_value);
server_.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sockfd,(struct sockaddr *)(&server_),SIZE) == -1){
perror("connect");
exit(1);
}
if((read_count = read(sockfd,buf,1024)) == -1){
perror("read");
exit(1);
}
buf[read_count] = '\0';
printf("#----#----#:%s\n",buf);
if(write(sockfd, mybuf,6) == -1){
perror("write");
exit(1);
}
close(sockfd);
exit(0);
return 0;
}
② linux socket 连接超时 怎么解决
今天发现自己的系统存在很严重缺陷,当前台关闭的时候后台就无法正常工作,原因很好定位,后台的socket连接超时时间过长,系统默认时间好像是75秒,于是找资料,根据下边文章中的内容解决了,把超时时间设为5秒后,感觉好多了。看来还有好多东西需要慢慢挖掘阿!
如何设置socket的Connect超时(linux)
[From]http://dev.cbw.com/c/c/200510195601_4292587.shtml
1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数
2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。
3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)
4.调用select( socket, &rset, &wset, NULL, timeout )
返回0表示connect超时
如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。
[From]http://www.ycgczj.com.cn/34733.html
网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注: select函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的主机的时候,会塞得你受不了的。我也废话少说,先说说我的方法,如果你觉得你已掌握这种方法,你就不用再看下去了,如果你还不了解,我愿意与你分享。本文是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。
Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写(注意,是可写)
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)
如果你对网络编程很熟悉的话,其实我一说出这个过程你就知道怎么写你的程序了,下面给出我写的一段程序,仅供参考。
/******************************
* Time out for connect()
* Write by Kerl W
******************************/
#include <sys/socket.h>
#include <sys/types.h>
#define TIME_OUT_TIME 20 //connect超时时间20秒
int main(int argc , char **argv)
{
………………
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) exit(1);
struct sockaddr_in serv_addr;
………//以服务器地址填充结构serv_addr
int error=-1, len;
len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctl(sockfd, FIONBIO, &ul); //设置为非阻塞模式
bool ret = false;
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
tm.tv_set = TIME_OUT_TIME;
tm.tv_uset = 0;
FD_ZERO(&set);
FD_SET(sockfd, &set);
if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if(error == 0) ret = true;
else ret = false;
} else ret = false;
}
else ret = true;
ul = 0;
ioctl(sockfd, FIONBIO, &ul); //设置为阻塞模式
if(!ret)
{
close( sockfd );
fprintf(stderr , "Cannot Connect the server!n");
return;
}
fprintf( stderr , "Connected!n");
//下面还可以进行发包收包操作
……………
}
以上代码片段,仅供参考,也是为初学者提供一些提示,主要用到的几个函数,select, ioctl, getsockopt都可以找到相关资料,具体用法我这里就不赘述了,你只需要在linux中轻轻的敲一个man <函数名>就能够看到它的用法。
此外我需要说明的几点是,虽然我们用ioctl把套接口设置为非阻塞模式,不过select本身是阻塞的,阻塞的时间就是其超时的时间由调用select 的时候的最后一个参数timeval类型的变量指针指向的timeval结构变量来决定的,timeval结构由一个表示秒数的和一个表示微秒数(long类型)的成员组成,一般我们设置了秒数就行了,把微妙数设为0(注:1秒等于100万微秒)。而select函数另一个值得一提的参数就是上面我们用到的fd_set类型的变量指针。调用之前,这个变量里面存了要用select来检查的描述符,调用之后,针对上面的程序这里面是可写的描述符,我们可以用宏FD_ISSET来检查某个描述符是否在其中。由于我这里只有一个套接口描述符,我就没有使用FD_ISSET宏来检查调用select之后这个sockfd是否在set里面,其实是需要加上这个判断的。不过我用了getsockopt来检查,这样才可以判断出这个套接口是否是真的连接上了,因为我们只是变相的用select来检查它是否连接上了,实际上select检查的是它是否可写,而对于可写,是针对以下三种条件任一条件满足时都表示可写的:
1)套接口发送缓冲区中的可用控件字节数大于等于套接口发送缓冲区低潮限度的当前值,且或者i)套接口已连接,或者ii)套接口不要求连接(UDP方式的)
2)连接的写这一半关闭。
3)有一个套接口错误待处理。
这样,我们就需要用getsockopt函数来获取套接口目前的一些信息来判断是否真的是连接上了,没有连接上的时候还能给出发生了什么错误,当然我程序中并没有标出那么多状态,只是简单的表示可连接/不可连接。
下面我来谈谈对这个程序测试的结果。我针对3种情形做了测试:
1. 目标机器网络正常的情况
可以连接到目标主机,并能成功以阻塞方式进行发包收包作业。
2. 目标机器网络断开的情况
在等待设置的超时时间(上面的程序中为20秒)后,显示目标主机不能连接。
3. 程序运行前断开目标机器网络,超时时间内,恢复目标机器的网络
在恢复目标主机网络连接之前,程序一只等待,恢复目标主机后,程序显示连接目标主机成功,并能成功以阻塞方式进行发包收包作业。
以上各种情况的测试结果表明,这种设置connect超时的方法是完全可行的。我自己是把这种设置了超时的connect封装到了自己的类库,用在一套监控系统中,到目前为止,运行还算正常。这种编程实现的connect超时比起修改系统参数的那种方法的有点就在于它只用于你的程序之中而不影响系统。
③ linux 下用socket 文件传输问题(UDP)
要下班了,时间急,不写代码了先给你一个思路
1 实现最简单的udp socket 模型,实现发送一个字符串。
2 实现一个简单的打开文件,读取文件的例子,如用fgets(),类似的函数有很多,然后再把读取的文件内容忘另一个文件里写(相关函数fopen(),write(),read())。
3 把上面两个函数结合到一起,在客户端实现打开要传送的文件,按一定的大小读取,读取后调用sendto()发送到服务器端。在服务器端创建一个文件,然后调用recvfrom()接受客户端发送过来的数据,向来是创建的那个文件中写。
下面是改好的udp发送文件的例子。
服务器端程序的编译
gcc -o file_server file_server
客户端程序的编译
gcc -o file_client file_client.c
服务器程序和客户端程应当分别运行在2台计算机上.
服务器端程序的运行,在一个计算机的终端执行
./file_server
客户端程序的运行,在另一个计算机的终端中执行
./file_client 运行服务器程序的计算机的IP地址
根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上
在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序,
服务器端程序的运行,在一个终端执行
./file_server
客户端程序的运行,在另一个终端中执行
./file_client 127.0.0.1
说明: 任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1
//////////////////////////////////////////////////////////////////////////////////////
// file_server.c 文件传输顺序服务器示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是服务器的代码
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
*/
#define HELLO_WORLD_SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr, pcliaddr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的据报套接字(UDPt,用server_socket代表服务器socket
// 创建数据报套接字(UDP)
int server_socket = socket(PF_INET,SOCK_DGRAM,0);
if( server_socket < 0)
{
printf("Create Socket Failed!");
exit(1);
}
//把socket和socket地址结构联系起来
if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
{
printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
exit(1);
}
while (1) //服务器端要一直运行
{
//定义客户端的socket地址结构client_addr
struct sockaddr_in client_addr;
socklen_t n = sizeof(client_addr) ;
int length;
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
length = recvfrom(new_server_socket,buffer,BUFFER_SIZE,0,&pcliaddr,&n);
if (length < 0)
{
printf("Server Recieve Data Failed!\n");
break;
}
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
// int fp = open(file_name, O_RDONLY);
// if( fp < 0 )
FILE * fp = fopen(file_name,"r");
if(NULL == fp )
{
printf("File:\t%s Not Found\n", file_name);
}
else
{
bzero(buffer, BUFFER_SIZE);
int file_block_length = 0;
// while( (file_block_length = read(fp,buffer,BUFFER_SIZE))>0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf("file_block_length = %d\n",file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0)<0)
{
printf("Send File:\t%s Failed\n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
}
// close(fp);
fclose(fp);
printf("File:\t%s Transfer Finished\n",file_name);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
// file_client.c 文件传输客户端程序示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是客户机的代码
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
*/
#define HELLO_WORLD_SERVER_PORT 6666
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: ./%s ServerIPAddress\n",argv[0]);
exit(1);
}
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_DGRAM,0);
if( client_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}
//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
{
printf("Server IP Address Error!\n");
exit(1);
}
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
printf("Please Input File Name On Server:\t");
scanf("%s", file_name);
char buffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);
strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
socklen_t n = sizeof(server_addr) ;
sendto(client_socket,buffer,BUFFER_SIZE,0,(struct sockaddr*)&server_addr,n);
// int fp = open(file_name, O_WRONLY|O_CREAT);
// if( fp < 0 )
FILE * fp = fopen(file_name,"w");
if(NULL == fp )
{
printf("File:\t%s Can Not Open To Write\n", file_name);
exit(1);
}
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
int length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
{
if(length < 0)
{
printf("Recieve Data From Server %s Failed!\n", argv[1]);
break;
}
// int write_length = write(fp, buffer,length);
int write_length = fwrite(buffer,sizeof(char),length,fp);
if (write_length<length)
{
printf("File:\t%s Write Failed\n", file_name);
break;
}
bzero(buffer,BUFFER_SIZE);
}
printf("Recieve File:\t %s From Server[%s] Finished\n",file_name, argv[1]);
return 0;
}
④ 想问一个 关于linux下 socket编程的问题! 请进
1、 accept函数中,第三个参数原型是 socklen_t的,这是个什么啊? 编译的时候总是 说 它和int 的转换无效! 应该怎么修改?
a.accept的函数原型为int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);最后一个参数是socklen_t类型,没记错的话,他是unsigned int类型。所以誉做拍会有gcc会warning(g++则报错,g++更严格)
2、编译的时候 命令行输入的是:
./TCPServer (服务器IP) (端口号)
我想问的是,这个 服务器IP和 端口号 在程序里面是怎么体现出来的?
是不是 那个 if(argc!=2) 决定的啊? 也就是命令行必须 输出2个字符串。
如果输出 三个字符串(包括端口号) 能行么? 哪位高手帮帮我啊!
a.服务器的IP是写死在庆羡程序里的,这句,
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);INADDR_ANY表示让协议栈自己选IP地址(针对多IP的情况);端口体现在这句 server_addr.sin_port=htons(portnumber);程序要求你输入两个字符串,其中第一个为程序名,第二个为端口号。比如你编译出来的程序叫server,则命令为server 8888,就可以执行了。注意这里的argc等于几表示连程序名称在内总共有几个字符串。
4、 最后的 close()函数 作用范围不明!
因为你调用了socket函数打开了一个描述字sockfd,所以这里要把他关闭。
newfd是你accept返回的描述字,前面已经关了,这两个是不一样的。sockfd用来监听,newfd用来与建立连接的对端通讯。
另外,你露了头文件,所以warning
#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 WAITBUF 10
#include <unistd.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t sin_size;
int portnumber;
char hello[]="Hello! Socket communication world!\n";
if(argc!=2)
{
fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
exit(1);
}
/*端口号不对,退出*/
if((portnumber=atoi(argv[1]))<0)
{
fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
exit(1);
}
/*服务器端开始建立socket描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit(1);
}
/*服务器端填充 sockaddr结构*/
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
/*自动填充主机IP*/
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(portnumber);
/*捆绑sockfd描述符*/
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
exit(1);
}
/*监听sockfd描述符*/
if(listen(sockfd, WAITBUF)==-1)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
exit(1);
}
while(1)
{
/*服务器阻塞,直到客户程序建立连接*/
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));
if(send(new_fd,hello,strlen(hello),0)==-1)
{
fprintf(stderr,"Write Error:%s\n",strerror(errno));
exit(1);
}
/*这个通信已经结束*/
close(new_fd);
/*循环下一个*/
}
close(sockfd);
exit(0);
}