×

Linux下SOCKET编程_内核socket编程

前端技术网 前端技术网 发表于2024-01-18 20:21:35 浏览3117 评论0

抢沙发发表评论

一、linux下的 socket编程问题!

第一个问题:

对,是那样的,用open打开文件,用read读取文件,在发送给对方,接收方接收到后,写入文件就可以了。不过在这个过程中最好别用字符串函数,除非你很熟悉。

Linux下SOCKET编程_内核socket编程

第二个问题

首先你得去搞清楚什么是线程,什么是进程,fork出来的叫进程,pthread_create出来的才叫线程。服务器有很多种模型(多进程,多线程,select,epoll模型,这个我的blog上有,famdestiny.cublog.cn),不一定要用多进程。

给你写了个代码,自己先看看:

注意,在自己的目录下创建一个叫pserverb的文件,程序会把这个文件**成test文件。你可以自己根据需要改改

server:

#include<stdio.h>

Linux下SOCKET编程_内核socket编程

#include<sys/socket.h>

#include<netinet/in.h>

#include<errno.h>

#include<signal.h>

#include<sys/wait.h>

#include<sys/types.h>

#include<string.h>

#include<stdlib.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<unistd.h>

#define SERV_PORT 5358

#define MAX_CONN 10

#define BUF_LEN 1024

void str_echo(FILE*fp, int sockfd){

ssize_t nread;

int file_fd;

char buf[BUF_LEN]={0};

file_fd= open("test", O_WRONLY| O_TRUNC| O_CREAT, 0755);

while(1){

bzero(buf, BUF_LEN);

if((nread= read(sockfd, buf, BUF_LEN))==-1){

if(errno== EINTR){

continue;

}

else{

printf("readn error:%s\n", strerror(errno));

continue;

}

}

else if(nread== 0){

break;

}

else{

printf("%s\n", buf);

write(file_fd, buf, nread);

}

}

close(file_fd);

}

void sig_chld(int sig){

pid_t pid;

int state;

while((pid= waitpid(-1,&state, WNOHANG))> 0){

printf("child process%d exited.", pid);

}

return;

}

int main(int argc, char**argv)

{

int listenfd, connfd;

socklen_t cliaddrlen;

pid_t childpid;

struct sockaddr_in servaddr, cliaddr;

if((listenfd= socket(AF_INET, SOCK_STREAM, 0))==-1){

printf("socket error:%s\n", strerror(errno));

return 0;

}

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family= AF_INET;

servaddr.sin_addr.s_addr= htonl(INADDR_ANY);

servaddr.sin_port= htons(SERV_PORT);

if(bind(listenfd,(struct sockaddr*)&servaddr, sizeof(servaddr))==-1){

printf("bind error:%s\n", strerror(errno));

return 0;

}

if(listen(listenfd, MAX_CONN)==-1){

printf("listen error:%s\n", strerror(errno));

return 0;

}

signal(SIGCHLD, sig_chld);

while(1){

cliaddrlen= sizeof(cliaddr);

if((connfd= accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen))==-1){

if(errno== EINTR){

continue;

}

else{

printf("accept error:%s\n", strerror(errno));

continue;

}

}

if((childpid= fork())== 0){

close(listenfd);

str_echo(stdin, connfd);

exit(0);

}

else if(childpid> 0){

close(connfd);

}

else{

printf("fork error!\n");

continue;

}

}

}

client:

#include<stdio.h>

#include<unistd.h>

#include<errno.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<string.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdlib.h>

#define SERV_ADDR"127.0.0.1"

#define SERV_PORT 5358

#define BUF_LEN 1024

void str_cli(char*path, int sockfd)

{

char sendbuf[BUF_LEN]={0};

int fd, n;

if((fd= open("./pserverb", O_RDONLY))==-1){

printf("%s\n", strerror(errno));

exit(0);

}

while((n= read(fd, sendbuf, BUF_LEN))!= 0){

if(n< 0){

printf("%s\n", strerror(errno));

exit(0);

}

write(sockfd, sendbuf, n);

bzero(sendbuf, BUF_LEN);

}

close(fd);

return;

}

int main(int argc, char**argv)

{

int fd;

struct sockaddr_in servaddr;

fd= socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family= AF_INET;

servaddr.sin_addr.s_addr= inet_addr(SERV_ADDR);

servaddr.sin_port= htons(SERV_PORT);

if(connect(fd,(struct sockaddr*)&servaddr, sizeof(servaddr))==-1){

printf("connect error:%s\n", strerror(errno));

return 0;

}

str_cli(argv[1], fd);

return 0;

}

二、Windows Socket和Linux Socket编程的区别

SOCKET在原理上应该是一样的,只是不同系统的运行机置有些不同。

Socket编程 windows到Linux代码移植遇到的问题

1、一些常用函数的移植

2、网络

socket相关程序从windows移植到linux下需要注意的

1)头文件

windows下winsock.h/winsock2.h

linux下sys/socket.h

错误处理:errno.h

其他常用函数的头文件可到命令行下用man指令查询。

2)初始化

windows下需要用WSAStartup

linux下不需要(很方便),直接可以使用

3)关闭socket

windows下closesocket(...)

linux下close(...)

4)类型

windows下SOCKET

在linux下为int类型

5)绑定地址的结构体

名称相同,都是struct sockaddr、struct sockaddr_in,这两者通常转换使用;

在Windows下面名称都是大写,而在Linux下为小写

常用:

Linux下:

sockaddr_in destAddr;

destAdd.sin_family=AF_INET;

destAddr.sin_port=htons(2030);

destAddr.sin_addr.s_addr=inet_addr("192.168.1.1");

Windows下:

SOCKADDR_IN destAddr;

destAddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.1");

但结构体中成员的名称不同

Windows中结构体成员

struct sockaddr_in{

short sin_family;

u_short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

struct sockaddr{

u_short sa_family;

char sa_data[14];

};

struct in_addr{

union{

struct{ u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;

struct{ u_short s_w1,s_w2;} S_un_w;

u_long S_addr;

} S_un;

};

下面的一些宏可以使windows下的程序移植到linux下(通过类型的重新定义,使代码具有linux和windows下的移植性)

[cpp] view plaincopy

#ifdef WIN32

typedef int socklen_t;

typedef int ssize_t;

#endif

#ifdef __LINUX__

typedef int SOCKET;

typedef unsigned char BYTE;

typedef unsigned long DWORD;

#define FALSE 0

#define SOCKET_ERROR(-1)

#endif

[cpp] view plaincopy

#ifdef WIN32

typedef int socklen_t;

typedef int ssize_t;

#endif

#ifdef __LINUX__

typedef int SOCKET;

typedef unsigned char BYTE;

typedef unsigned long DWORD;

#define FALSE 0

#define SOCKET_ERROR(-1)

#endif

6)获取错误码

windows下getlasterror()/WSAGetLastError()

linux下errno变量

7)设置非阻塞

windows下ioctlsocket()

linux下fcntl()<fcntl.h>

8)send函数最后一个参数

windows下一般设置为0

linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可能会导致程序退出。

9)毫秒级时间获取

windows下GetTickCount()

linux下gettimeofday()

10)数据类型的一些转化

通用的:

小端到大端(网络协议使用)的转换:htonl, htons

点分十进制IP和整数之间的相互转换:inet_addr()(该函数将点分十进制转为整数),inet_aton(),inet_ntoa(),inet_pton()(linux下独有该函数可以实现相互之间的转换)

使用到的头文件不相同,linux下用man命令查询。

另外注意:

linux下使用的套接字为伯克利套接字,因此在select()函数的使用上(第一个参数的设置)也有区别;

windows下为了与伯克利套接字匹配,第一个参数是无所谓,一般可设为0;

int maxfdp是一个整数值,是指**中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!

3、多线程

多线程:(win)process.h--〉(linux)pthread.h

_beginthread--> pthread_create

_endthread--> pthread_exit

三、想问一个 关于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);

}

感谢您的阅读!希望本文对解决您关于Linux下SOCKET编程_内核socket编程和Windows Socket和Linux Socket编程的区别的问题有所帮助。如果您还有其他疑问,欢迎随时向我们提问。